複数の検索単語での部分一致のためのSQL文の書き方がわからない

実現したいこと

英単語アプリでの検索機能を付ける作業において、与えられた複数の検索用語のどれかに一致すれば、そのレコードを抽出するようにしたい

前提

英単語を格納しているテーブルは英語、発音、日本語、例文、解説の5つのカラムで構成されており、検索文字列はテキストボックスでスペース区切りで複数指定できる状態です。
以下のコードの流れとしては、受け取ったスペース区切りの検索用文字列を配列にしてDBのテーブルを完全一致と部分一致で検索し、該当レコードを抽出するというものです。

PHP

1 const DB_COLUMNS_NUM = 5;2 $input = convertStringToArray($_REQUEST['search']);3 $placeholders = implode(',', array_fill(0, count($input), '?')); 4 $sql = "SELECT * FROM tango_table 5 WHERE tenglish IN ($placeholders) OR 6 tpronunciation LIKE ($placeholders) OR 7 tjapanese IN ($placeholders) OR 8 tsample LIKE ($placeholders) OR 9 tintro LIKE ($placeholders)";10 11 $stmt = $mysqli->prepare($sql);12 13 // 検索単語数 ✕ 5カラム分 の 's'14 $types = str_repeat('s', count($input) * DB_COLUMNS_NUM); 15 16 $likeConditions = [];17 foreach ($input as $word) {18 $likeConditions[] = "%$word%";19 }20 21 $bindParams = [$types];22 for ($i = 0; $i < DB_COLUMNS_NUM; $i++) {23 foreach ($likeConditions as &$value) {24 $bindParams[] = &$value;25 }26 }27 28 call_user_func_array([$stmt, 'bind_param'], $bindParams);29 30 $stmt->execute();31 32 $result = $stmt->get_result();

発生している問題

検索単語が1語の場合は正常に処理されるのですが、2語以上になると以下のようなエラーになります

Fatal error: Uncaught mysqli_sql_exception: Operand should contain 1 column(s) in the line "$stmt = $mysqli->prepare($sql);"

該当のソースコード

PHP

1$stmt = $mysqli->prepare($sql);

考えたこと

変数$placeholdersは検索単語数分の?を持ち、それが各カラムのINやLIKEの後ろに配置されてるので変数$typesは(検索単語数✕カラム数)としています。しかしこの辺の考えが怪しいのではないかと思っています。LIKEに複数の検索用単語を渡すにはもっと別の処理をしないといけないのではないかと思っています。検索単語が1つならうまくいくということは、LIKEの後ろのプレースホルダは1個でないといけないのかな。ではどうやって複数の検索単語を渡すかという問題になります。それで、検索用語ごとにSQL文をまるごと作って連結すればできるなら、以下のように検索単語数分の(tenglish LIKE ? OR 〜OR tintro LIKE ? )を繰り返したようなSQL文を作ればいいのかなと。

SQL

1 "SELECT * FROM tango_table WHERE tenglish LIKE ? OR tpronunciation LIKE ? OR tjapanese LIKE ? OR tsample LIKE ? OR tintro LIKE ? OR tenglish LIKE ? OR tpronunciation LIKE ? ... "

あと似たようなケースのコードを拾ってきたのですがなんか違う感じがしています

PHP

1 $placeholders = implode(' OR ', array_fill(0, count($input), 'tenglish LIKE ?'));2 $sql = "SELECT * FROM tango_table WHERE $placeholders OR tpronunciation LIKE ? OR tjapanese LIKE ? OR tsample LIKE ? OR tintro LIKE ?";3 $stmt = $mysqli->prepare($sql);4 5 $types = str_repeat('s', count($input) + 4); // 検索単語数 + 固定の4つの 's'6 $bindParams = array_merge([$types], $likeConditions, ["%{$_POST['search']}%", "%{$_POST['search']}%", "%{$_POST['search']}%", "%{$_POST['search']}%"]);7 $stmt->bind_param(...$bindParams);

コメントを投稿

0 コメント