###前提・実現したいこと
PHP&MySQL初心者です。
分からない事があるため、質問させて頂きます。
PHP+MySQLでユーザーがフォームを複製でき、検索オプションを指定できる検索システムを作成しています。
検索フォームからの入力データは、以下のような多次元配列に整形しています。
$name_arr = [['検索オプション','検索キーワード'],['検索オプション','検索キーワード'],['検索オプション','検索キーワード'],・・・];
該当のキーワードをAND検索にするかOR検索にするかユーザーが自由に選択できるため、どの様な順番になるかは予測できません。
どの様な順番でも検索結果が同じならば良いのですが、順番が違うと検索結果が異なってしまいます。
検索結果の差異を無くしたいので、どうかアドバイスよろしくお願いします。
###発生している問題・エラーメッセージ
AND条件のキーワードとOR条件のキーワードが混じっている場合、 AND条件のキーワードが先頭なら問題なく検索されるのですが、 OR条件のキーワードが先頭の場合は、検索結果がAND条件が先頭の時に比べ、少なくなってしまいます。 AND条件が先頭 $name_arr = [['AND','検索キーワード'],['or','検索キーワード2'],['or','検索キーワード3']]; OR条件が先頭 $name_arr = [['OR','検索キーワード2'],['OR','検索キーワード3'],['AND','検索キーワード']];または $name_arr = [['OR','検索キーワード2 検索キーワード3'],['AND','検索キーワード']]; 作成されるsql文は、どちらを先頭にしても同じです。 SELECT * FROM data WHERE name LIKE ? AND (name LIKE ? OR name LIKE ?) 例 MySQLの「name」に「みかんのジュース」と「みかんのお酒」が入っています。 $name_arr = [['AND','みかん'],['OR','ジュース'],['OR','お酒']]; で検索すると「みかんのジュース」と「みかんのお酒」が表示されますが、 $name_arr = [['OR','ジュース'],['OR','お酒'],['AND','みかん']]; で検索すると「みかんのジュース」しか表示されません。
###該当のソースコード(検索フォーム部分)
HTML
1キーワードは以下のどちらかの形式で入力され、GETで渡されます。 2<div> 3<input type="text" size="10" name="name[]"> 4<select name="name_op[]"> 5<option value="AND" selected>を含む</option> 6<option value="OR">をいずれか含む</option> 7</select> 8</div> 9 10または 11 12<div> 13<select name="test[]"> 14<option selected></option> 15<option>検索キーワード</option> 16<option>検索キーワード2</option> 17<option>検索キーワード3</option> 18</select> 19<select name="test_op[]"> 20<option value="AND" selected>を含む</option> 21<option value="OR">をいずれか含む</option> 22</select> 23</div> 24また、検索フォームの複製が可能なので、<div>〜</div>が複製される事があります。 25 26 27検索フォーム 28<form action="" method="get"> 29<table> 30<tr> 31<td>名前</td> 32<td class="search-item2 name_form"> 33<button type="button" value="追加" id="name_add">フォーム追加</button> 34<div id="name_input"> 35<input type="text" size="10" name="name[]"> 36<select name="name_op[]"> 37<option value="AND" selected>を含む</option> 38<option value="OR">をいずれか含む</option> 39<option value="NOT">を含まない</option> 40</select> 41</div> 42</td> 43</tr> 44<tr> 45<td colspan="2"><input type="submit" value=" 検索 "></td> 46</tr> 47</table> 48</form> 49 50名前のフォームを3つに複製した場合 51<form action="" method="get"> 52<table> 53<tr> 54<td>名前</td> 55<td class="search-item2 name_form"> 56<button type="button" value="追加" id="name_add">フォーム追加</button> 57<div id="name_input"> 58<input type="text" size="10" name="name[]"> 59<select name="name_op[]"> 60<option value="AND" selected>を含む</option> 61<option value="OR">をいずれか含む</option> 62<option value="NOT">を含まない</option> 63</select> 64</div> 65<div id="name_input"> 66<input type="text" size="10" name="name[]"> 67<select name="name_op[]"> 68<option value="AND" selected>を含む</option> 69<option value="OR">をいずれか含む</option> 70<option value="NOT">を含まない</option> 71</select> 72</div> 73<div id="name_input"> 74<input type="text" size="10" name="name[]"> 75<select name="name_op[]"> 76<option value="AND" selected>を含む</option> 77<option value="OR">をいずれか含む</option> 78<option value="NOT">を含まない</option> 79</select> 80</div> 81</td> 82</tr> 83<tr> 84<td colspan="2"><input type="submit" value=" 検索 "></td> 85</tr> 86</table> 87</form> 88
###該当のソースコード(PHP部分)
PHP
1$sql = 'SELECT * FROM data'; 2 3$conditions = []; 4$parameters = []; 5 6// 検索条件を作成 7if (array_filter($_GET['name'], 'strlen')) { 8 $name_get = $_GET['name']; 9 $name_count = count($name_get); 10 $s = 0; 11 for ($s; $s < $name_count; ++$s) { 12 $name_arr[] = array($_GET['name_op'][$s], $name_get[$s]); //検索キーワードと検索オプションを関連付け 13 } 14 foreach ($name_arr as $name_arr2) { 15 $name_arr2 = array_map('trim', $name_arr2); 16 if ($name_arr2[0] === 'AND' and !empty($name_arr2[1])) { //検索オプションがANDの場合 17 $name_arr3 = explode(" ",$name_arr2[1]); 18 foreach ($name_arr3 as $name) { 19 $conditions[] = 'concat(name,name_yomi) LIKE ?'; 20 $parameters[] = array( 21 'value' => "%{$name}%", 22 'type' => PDO::PARAM_STR 23 ); 24 } 25 } else if ($name_arr2[0] === 'OR' and !empty($name_arr2[1])) { //検索オプションがORの場合 26 $name_arr3 = explode(" ",$name_arr2[1]); 27 foreach ($name_arr3 as $name) { 28 $conditions2[] = 'concat(name,name_yomi) LIKE ?'; 29 $parameters[] = array( 30 'value' => "%{$name}%", 31 'type' => PDO::PARAM_STR 32 ); 33 } 34 } 35 } 36} 37 38// 条件を連結 39if (!empty($conditions) and empty($conditions2)) { 40 $sql .= ' WHERE ' . implode(' AND ', $conditions); 41} else if (!empty($conditions2) and empty($conditions)) { 42 $sql .= ' WHERE ' . '(' . implode(' OR ', $conditions2) . ')'; 43} else if (!empty($conditions) and !empty($conditions2)) { 44 $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' AND ' . '(' . implode(' OR ', $conditions2) . ')'; 45} 46 47// プリペアドステートメントを作成 48$stmt = $pdo->prepare($sql); 49 50// 値をバインド 51$i = 1; 52foreach ($parameters as $param) { 53 $stmt->bindValue($i++, $param['value'], $param['type']); 54} 55
###試したこと
$conditionsと$conditions2が揃っている場合のimplodeを逆にしてみたところ、
or条件が先頭の場合は上手く行きましたが、and条件が先頭の場合に上手く行かなくなってしまいました。
###補足情報(言語/FW/ツール等のバージョンなど)
PHP7.1.4
MySQL5.7
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/29 13:46
2017/05/29 14:00 編集
2017/05/29 14:52
2017/05/30 01:14
2017/05/30 09:09