【问题标题】:MySQL, select records with at least X characters matchingMySQL,选择至少有 X 个字符匹配的记录
【发布时间】:2010-11-12 02:29:14
【问题描述】:

我正在努力完成以下工作。假设我们有一个包含这些字段(ID、内容)的表

1 |苹果

2 |菠萝

3 |应用

4 |国家

现在,我正在寻找一个可以告诉我所有可能的常见匹配项的函数。例如,如果参数为“3”,则该函数将返回出现在多于一条记录中的 3 个字符中的所有可能字符串。

在这种情况下,我得到 "app","ppl","ple","ati","tio","ion"

如果参数是“4”,我得到:“appl”,“pple”,“atio”,“tion”

如果参数是“5”,我得到:“apple”,“ation”

如果参数为“6”,则返回 nohting。

直到现在,我还没有找到实现这个功能的函数。

谢谢!

一些额外的信息: 我在带有 MySQL 数据库的 PHP 脚本中使用它。我真的只想给出字符数量作为参数,当然还有要搜索的表格。

【问题讨论】:

  • 除了表示长度的数字之外,您还打算将什么作为参数发送给查询?这将基于什么编码语言?

标签: mysql string-matching


【解决方案1】:

嗯,这有点难看,但它确实工作正常。它是通用 SQL,适用于任何环境。只需生成大于您正在读取的字段的最大长度的子字符串的多个选择。将函数中的数字 50 更改为超出字段长度的数字。它可能会返回一个非常长的查询,但就像我说的那样,它会正常工作。以下是 Python 中的示例:

import sqlite3

c = sqlite3.connect('test.db')

c.execute('create table myTable (id integer, content varchar[50])')
for id, content in ((1,'apple'),(2,'pineapple'),(3,'application'),(4,'nation')):
    c.execute('insert into myTable values (?,?)', [id,content])

c.commit();

def GenerateSQL(substrSize):
    subqueries = ["select substr(content,%i,%i) AS substr, count(*) AS myCount from myTable where length(substr(content,%i,%i))=%i group by substr(content,%i,%i) " % (i,substrSize,i,substrSize,substrSize,i,substrSize)  for i in range(50)]
    sql = 'select substr FROM \n\t(' + '\n\tunion all '.join(subqueries) + ') \nGROUP BY substr HAVING sum(myCount) > 1'
    return sql

print GenerateSQL(3)

print c.execute(GenerateSQL(3)).fetchall()

生成的查询如下:

select substr FROM 
    (select substr(content,0,3) AS substr, count(*) AS myCount from myTable where length(substr(content,0,3))=3 group by substr(content,0,3) 
    union all select substr(content,1,3) AS substr, count(*) AS myCount from myTable where length(substr(content,1,3))=3 group by substr(content,1,3) 
    union all select substr(content,2,3) AS substr, count(*) AS myCount from myTable where length(substr(content,2,3))=3 group by substr(content,2,3) 
    union all select substr(content,3,3) AS substr, count(*) AS myCount from myTable where length(substr(content,3,3))=3 group by substr(content,3,3) 
    union all select substr(content,4,3) AS substr, count(*) AS myCount from myTable where length(substr(content,4,3))=3 group by substr(content,4,3) 
    ... ) 
GROUP BY substr HAVING sum(myCount) > 1

它产生的结果是:

[(u'app',), (u'ati',), (u'ion',), (u'nat',), (u'pin',), (u'ple',), (u'ppl',), (u'tio',)]

【讨论】:

  • 我会试试这个,如果我的服务器爆炸了会通知你的;)谢谢
【解决方案2】:

很抱歉,我有一段时间没有玩 php,而且我没有合适的测试环境,但我很快在 c# 3.5 中设计了一种方法

伪代码:用指定长度的字符串和旁边的出现次数构建一个表。选择其中 count > 1:

    static void Main(string[] args)
    {

        string[] data = { "apple", "pinapple", "application", "nation" };
        string[] result = my_func(3,data);

        foreach (string str in result)
        {
            Console.WriteLine(str);
        }
        Console.ReadKey();
    }

    private static string[] my_func(int l, string[] data)
    {
        Dictionary<string,int> dict = new Dictionary<string,int>();
        foreach (string str in data)
        {
            for (int i = 0; i < str.Length - l + 1; i++)
            {
                string part = str.Substring(i, l);
                if (dict.ContainsKey(part))
                {
                    dict[part]++;
                }else {
                    dict.Add(part,1);
                }
            }
        }
        var result = from k in dict.Keys
                where dict[k] > 1
                orderby dict[k] descending
                select k;

        return result.ToArray<string>();
    }

【讨论】:

  • 这看起来很有趣。我只是有点担心性能,因为您对字典进行的所有“快速调用”,在我的情况下都是 sql 查询。缓存包含 10k 条记录的表也可能不是一个好主意,但我会检查一下!
  • 你是对的,这段代码应该在服务器上运行,然后看起来它需要用 SQL 编写,但是你需要在 SQL 中迭代,这实际上是不可能的。我其实很喜欢 Greg 的回答,只是生成的 SQL 查询看起来很疯狂,而且它取决于字段长度。
【解决方案3】:

一个明显的选择是使用正则表达式。我没有这方面的经验,但这可能对您有所帮助: http://dev.mysql.com/doc/refman/5.1/en/regexp.html

你需要找到一个合适的表达式来匹配你所需要的。

【讨论】:

  • 这不是很明显。我们正在讨论运行随机正则表达式并将结果与​​表中的所有其他记录进行匹配。我看不到任何涉及正则表达式的 SQL。
  • 如上所述,这只是解决方案的一小部分。我不知道要寻找的字符。使用 5 个字符,如果我随机执行,这将提供 2^5 个正则表达式查询。不幸的是,这不适合这个问题。
  • @Machine 我想我直到重新阅读它才完全理解这个问题。同意,我的“明显”选项毕竟不适用。我真的不认为这可以通过仅使用 sql 查询来实现,但我当然希望被证明是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多