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

  • 0
    いいね
  • 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 ... 他に条件があればここに書く ';
    

    回答に対しての反応

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