SQL:查询搜索所有可能的单词

时间:2011-10-13 16:40:35

标签: php mysql sql

我有一个带有输入框的表单,用户可以在其中指定其名称,名称可以是两个或多个单词,例如John SmithJohn Michael Smith

我必须编写一个查询,返回包含所显示名称中所有单词的记录。因此查询将返回具有所有这些单词的名称的记录,但可能具有不同的顺序。

例如,如果搜索字符串为John Michael Smith,则查询应该能够返回名称为Michael John SmithMichael Smith JohnJohn Smith Michael或某些组合的记录这些话就在那里。可以看出,只返回仍然包含名称字段中所有单词的记录,但可能具有不同的顺序。但是,它应该返回不包含部分名称的结果,例如,John Michael不应该返回,因为它没有Smith

我试过这样的查询:

SELECT id, name FROM users WHERE
     name LIKE '%Michael%' &&
     name LIKE '%Smith%' &&
     name LIKE '%John%'

同样的问题发生在:

SELECT * FROM users WHERE MATCH (name)
    AGAINST ('+Michael +Smith +John' IN BOOLEAN MODE);

两个查询都返回John Michael而不是包含所有三个单词的记录:(

我无法弄清楚如何将查询写入需求,以便我拥有。请帮忙。

3 个答案:

答案 0 :(得分:2)

使用fulltext index。这是最简单/最快捷的方法。否则,您将无法解析搜索字符串,转换

John Michael Smith

SELECT ... WHERE (name LIKE '%John%') OR (name LIKE '%Michael%') OR (name LIKE '%Smith%')
由于LIKE %..%搜索无法使用索引,因此很快就会感到痛苦,并且执行起来很慢。

请注意,全文索引目前仅限于MyISAM表,因此如果您使用的是InnoDB,则必须使用变通办法(MyISAM格式的并行表可以保存带有触发器的可搜索数据,以保持两个副本同步)。显然,InnoDB的Fulltext在开发流程中是最终,但它还没有。

答案 1 :(得分:1)

如果将名称保存在“name”字段中,则sql查询应该是这样的

首先按空格分解字符串

$params = explode(' ', $input_name);

然后将此附加到您的查询中:

    $i = 0;
    $q= '';
    foreach($params as $p){
        $p = strtolower($p);
        if($i > 0) $q.= " and ";
        $q.= "LOWER(name) like '%$p%'";
        $i++;
    }

$query="select .... where ".$q; 

需要较低的东西才能使其不区分大小写。

答案 2 :(得分:1)

无论您将哪个变量设置为此输入的值,您都希望使用explode: http://php.net/manual/en/function.explode.php

$names = explode(' ', $userinput);

以空格作为分隔符。这将为您提供一个包含3个不同元素的数组(或者有许多元素)。

$names[0] = "John";
$names[1] = "Michael"
$names[2] = "Smith";

现在你需要通过strtolower运行它们,这样就不会出现问题了。

http://us3.php.net/manual/en/function.strtolower.php

 foreach ($names as $name)
{
  $name = strtolower($name);
}

现在我们有了

$names[0] = "john";
$names[1] = "michael"
$names[2] = "smith";

接下来,您需要构建一个函数,以所有可能的顺序重新组合这些变量。但是因为您的阵列中可能包含1,2,3或4个元素,所以您不知道需要多少查询。所以你检查:

$numberofnames = count($names);

然后创建一个函数来构建不同的名称组合:

$namecombo = "";

function createNames($numberofnames)
{
 for($i=0; $i <= $Numberofnames; $i++)
 {
  $namecombos[i] .= $names[i];
 }

因此。这是一个不完整的答案,因为我们遇到了一个问题。你需要一个for循环来生成名称组合,但你还需要一个for循环来生成你需要多少个for循环。不是我能想到的一种编码方式。但是......希望这能让你更接近答案。

 for($i=0; $i <= $Numberofnames; $i++)
 {
  $secondnamecombo[i] = $names[$i - 1]
  etc...
 }
}