あなたが尋ねるクエリは少し複雑です。両方の列で一致を返す必要がありますが、両方の列が一致する場合は、単一の一致を破棄する必要があります。
これは、何らかの方法で、2 つの一致を必要とするクエリと 1 つの一致を必要とするクエリを実行し、結果を比較して適切なセットを返すことを意味します。
パフォーマンスに関しては、両方をフェッチする 1 つのクエリを実行し、結果を 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 と同一であるが、2 または 1 のいずれかを含む「matches」列が 1 つあるテーブルを取得します。WHERE
制限のため、0 を含めることはできません。2 つの一致のうちの 1 つが真であり、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
);
ただし、パフォーマンスが低下します。