我正在处理搜索脚本的一部分,其中解析提交的搜索字符串并将每个重要术语放入数组中。然后在WHERE子句中循环该数组以搜索MYSQL数据库中的多个列。这是一个示例SQL代码:
$sql = "SELECT title, question, tag1, tag2, tag3, tag4, tag5 FROM question WHERE ";
while(list($key,$val)=each($split_stemmed)){
if($val<>" " and strlen($val) > 0){
$sql .=
"(title LIKE '$val%'
OR question LIKE '$val%'
OR tag1 LIKE '$val%'
OR tag2 LIKE '$val%'
OR tag3 LIKE '$val%'
OR tag4 LIKE '$val%'
OR tag5 LIKE '$val%') OR";
}
}
$sql=substr($sql,0,(strLen($sql)-3));
$sql .= "GROUP BY q_id ORDER BY
((title LIKE '$val%') +
(question LIKE '$val%') +
(tag1 LIKE '$val%') +
(tag2 LIKE '$val') +
(tag3 LIKE '$val%') +
(tag4 LIKE '$val%') +
(tag5 LIKE '$val%')) desc, title asc";
我遇到的问题是让ORDER BY正常工作。 ORDER BY的目的是将查询结果从搜索字符串上的大多数命中顺序排列到最小。我的假设是我在某种程度上需要在ORDER BY子句中再次遍历数组,但我不确定如何执行此操作或者我是否在该假设中是正确的。那里有帮助吗?
我知道我可以使用mysql全文搜索更简单,但正在使用的表是InnoDB,所以我不认为这是一个选项。
答案 0 :(得分:0)
要考虑的几个问题......
1)ORDER BY表达式中的任何列tag1,tag2,tag3 ...中的NULL值将为整个表达式返回NULL。考虑:
SELECT 0 + NULL + 1 + 0
如果所有这些列都定义为NOT NULL,那么这不是问题。但更一般地说,你想要从NULL值绝缘......
ORDER BY ( IFNULL(title LIKE '$val%'),0) +
IFNULL(question LIKE '$val%'),0) +
IFNULL(tag1 LIKE '$val%'),0) +
IFNULL(tag2 LIKE '$val' ),0) +
- 或者 -
ORDER BY ( IFNULL(title ,'') LIKE '$val%') +
IFNULL(question,'') LIKE '$val%') +
IFNULL(tag1 ,'') LIKE '$val%') +
IFNULL(tag2 ,'') LIKE '$val' ) +
)
(看起来你在tag2上错过了基于模式的%
,但这完全有可能是故意的遗漏
2)您的查询中需要GROUP BY q_id
的原因并不清楚。
我建议您通过获取ORDER BY子句中的表达式进行测试,并将其复制到SELECT列表中,然后运行查询以查看它返回的值。
在MySQL中,如果将该表达式添加到SELECT列表并为其指定别名,则可以在ORDER BY上引用别名。
SELECT expr AS match_count, ...
FROM
ORDER BY match_count DESC
答案 1 :(得分:0)
您正在寻找的功能 - 搜索多列搜索字词并按相关性排序 - 正是full-text search的设计目标。如果可能的话,你应该使用它,因为它可以减少你的长期头痛。
如果您绝对必须以这种方式实现,那么有必要将 LIKE 语句移动到 SELECT 子句中,以便您可以对它们求和。像这样:
SUM (CASE WHEN title LIKE '$val%' THEN 1 ELSE 0 END
+ CASE WHEN question LIKE '$val%' THEN 1 ELSE 0 END
+ CASE WHEN tag1 LIKE '$val%' THEN 1 ELSE 0 END
... etc
) AS relevance
然后,只选择匹配项,您可以使用HAVING relevance > 0
。要订购,您只需使用ORDER BY relevance DESC
(因为上面的相关性列会为您提供匹配列数的计数)。