PHPで複数単語のAND検索するSQLを作る方法を教えてください

  • 2
    いいね
  • 2
    コメント

これは「コードを書いていて困ったときに、suinがチャットで質問に答えたり相談に乗るsuinのプログラミング相談室(仮)」で頂いた質問と僕の回答の要約です。

質問

「あああ いいい ううう」のようなスペース区切の単語をSQLでAND検索できるコードを書いてみたのですが、もっと良い書き方ってありませんか?

$keywords = ['A', 'B', 'C', 'D', 'E']; // 回答者注:SQLインジェクションが発生しない安全な文字列と仮定します。

switch (count($keywords)) {
case 1:
    $sql = "SELECT * FROM products WHERE name LIKE '%$keywords[0]%'";
    break;
case 2:
    $sql = "SELECT * FROM products WHERE name LIKE '%$keywords[0]%' AND name LIKE '%$keywords[1]%'";
    break;
case 3:
    $sql = "SELECT * FROM products WHERE name LIKE '%$keywords[0]%' AND name LIKE '%$keywords[1]%' AND name LIKE '%$keywords[2]%'";
    break;
case 4:
    $sql = "SELECT * FROM products WHERE name LIKE '%$keywords[0]%' AND name LIKE '%$keywords[1]%' AND name LIKE '%$keywords[2]%' AND name LIKE '%$keywords[3]%'";
    break;
case 5:
    $sql = "SELECT * FROM products WHERE name LIKE '%$keywords[0]%' AND name LIKE '%$keywords[1]%' AND name LIKE '%$keywords[2]%' AND name LIKE '%$keywords[3]%' AND name LIKE '%$keywords[4]%'";
    break;
}

suin: この方法だと、無限にcaseを増やさないとだめですもんね。
質問者: はい、そうなんです。

suinの回答

アルゴリズムに関する質問ですね。手順としては次のように実装します。

  1. キーワードをforeachで回して、name LIKE %xxx%といったLIKE句の配列を作る。
  2. 配列を文字列"AND"でくっつけて、WHERE句用の文字列を作る。
  3. 作ったWHERE句用文字列を全体のSQLにくっつける。
$keywords = ['A', 'B', 'C', 'D', 'E']; // 回答者注:SQLインジェクションが発生しない安全な文字列と仮定します。

// キーワードの数だけループして、LIKE句の配列を作る
$keywordCondition = [];
foreach ($keywords as $keyword) {
    $keywordCondition[] = 'name LIKE "%' . $keyword . '%"';
}

var_dump($keywordCondition); 
// ここで、 
// [ 'product_name LIKE "%hoge%"', 
//   'product_name LIKE "%fuga%"', 
//   'product_name LIKE "%piyo%"' ]
// という配列ができあがっている。

// これをANDでつなげて、文字列にする
$keywordCondition = implode(' AND ', $keywordCondition);

// あとはSELECT文にくっつけてできあがり♪
$sql = 'SELECT * FROM products WHERE ' . $keywordCondition . ' AND ... 他に条件があればここに書く ';

回答に対しての反応

なるほど! やってみます!