你问的问题有点复杂。您想在两列中返回匹配项,但如果两列都匹配,则必须丢弃单个匹配项。
这意味着,以一种或另一种方式,运行一个需要两个匹配项和一个需要一个匹配项的查询,比较结果并返回适当的集合。
性能方面,我认为最好运行一个查询来获取两者,然后在 PHP 中处理结果(您可以通过使用超级查询在 MySQL 中处理它们)。
所以:
// We split keywords
$keywords = array_unique(preg_split('/\s+/', $search));
$inset = array();
foreach($keywords as $keyword)
$inset[] = "'".mysql_real_escape_string($keyword)."'";
$sql_in = '('.implode(',', $inset).')';
$query = "SELECT *, IF(type IN $sql_in, 1,0)+IF(pattern IN $sql_in,1,0) AS matches FROM mytable WHERE (type IN $sql_in) OR (pattern IN $sql_in) ORDER BY matches DESC;";
上面使用了不鼓励的 mysql_ 函数。使用 PDO,这将是:
$keywords = array_unique(preg_split('/\s+/', $search));
// Generate a (?,?,?..?) template as long as $keywords
$sql_in = '('.implode(',', array_fill(0, count($keywords), '?')).')';
$query = "SELECT *, IF(type IN $sql_in, 1,0)+IF(pattern IN $sql_in,1,0) AS matches FROM mytable WHERE (type IN $sql_in) OR (pattern IN $sql_in) ORDER BY matches DESC;";
$st = $db->prepare($query);
$st->execute($keywords);
请注意,上面使用了完全匹配,因此“Boyd”将检索与“Boyd”的匹配,但“Boy”不会。使用%
匹配的字符来改变这种行为。
现在我们检索一个与 MyTable 相同但有一个额外列“matches”的表,其中包含 2 或 1。由于限制,不能包含 0 WHERE
:两个匹配项之一必须为真并计为 1。
2 将首先返回,所以我们可以这样做
if (!isset($matches))
$matches = $tuple['matches'];
else
if ($tuple['matches'] < $matches)
break;
也就是说,我们保存第一个(也是最高的)值,并且只为后续的元组接受该值。一旦出现劣质匹配,我们就退出循环并关闭光标。
这可以在 MySQL 中完成
SELECT * FROM ( the above query ) AS newTable
WHERE matches = (
SELECT MAX(matches) FROM ( the above query ) AS tmpTable
);
但它会导致性能损失。