質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

1回答

1840閲覧

and検索とor検索の順番を入れ替えると結果が変わる

taku0521

総合スコア5

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2017/05/29 12:01

編集2017/05/29 14:28

###前提・実現したいこと
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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ロジックがおかしいですよね

最初の条件にANDやORをつけてしまってるのは何に対してANDやORなのか
わかりません。またANDがORよりつよいので、ORを優先したい場合の
定義もあいまいです。

sample

HTML

1<form> 2<input type="text" size="10" name="name[]" value="aaa"> 3<select name="name_op[]"> 4<option value="AND">を含む</option> 5<option value="OR" selected>をいずれか含む</option> 6</select><br> 7<input type="text" size="10" name="name[]" value="bbb"> 8<select name="name_op[]"> 9<option value="AND" selected>を含む</option> 10<option value="OR">をいずれか含む</option> 11</select><br> 12<input type="text" size="10" name="name[]" value="ccc"> 13<select name="name_op[]"> 14<option value="AND" selected>を含む</option> 15<option value="OR">をいずれか含む</option> 16</select><br> 17<input type="submit" value="go"> 18</form> 19

これはどういったWHERE句になるのでしょうか?
それともvalueを分割してANDやORで検索するという意味でしょうか?

整理

話が噛み合わないので具体的に・・・

$name_arr = [[(※1)'AND','検索キーワード'],[(※2)'or','検索キーワード2'],[(※3)'or','検索キーワード3']];
↓↓↓
SELECT * FROM data WHERE name LIKE ? (※4)AND (name LIKE ? (※5)OR name LIKE ?)

※1が※4のANDになるとして、※5のorは※2と※3のどちらなのでしょうか?
またORが優先されるのはなにをみて判断しているのでしょうか?

普通に順番に適用すれば最初のANDは無視されて、
SELECT * FROM data WHERE name LIKE ? OR name LIKE OR name LIKE ?
にしかならないと思いますが?

投稿2017/05/29 12:21

編集2017/05/30 01:11
yambejp

総合スコア114843

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taku0521

2017/05/29 13:46

ご回答ありがとうございます。 検索フォーム部分を追加しました。 AND検索とOR検索のどちらにするかはユーザーが選べるため、OR検索を優先するのはユーザーの都合です。
yambejp

2017/05/29 14:00 編集

ちょっとHTMLでちゃんとUIを提示してみてください サンプルのせまました 上記でなくてもかまわないので、どういったHTMLでサブミットした時 どういったWHERE句を想定しているかいくつか例示してください
taku0521

2017/05/29 14:52

ご回答ありがとうございます。 検索フォーム部分を修正しました。 inputなので入力されたキーワードがそのままname[]に格納され、同様にname_op[]もユーザーが選択した物が格納されます。 inputを3つに複製し、それぞれに「みかん(を含む)」、「ジュース(をいずれか含む)」、「お酒(をいずれか含む)」と入力すると、「発生している問題・エラーメッセージ」の例で示した配列が表示されると思います。 想定するWHERE句は「発生している問題・エラーメッセージ」に記載していますが、これでは足りないでしょうか? なお、AND検索のみ、OR検索のみですと、問題なく想定通りの検索結果が表示されます。
yambejp

2017/05/30 01:14

改めて整理のため追記しました。 要求定義ができてませんので要件定義ができないため 仕様が確定しない状況だと思います AND A,OR B,OR Cが? AND (? OR ?)になるための必要条件を提示して下さい
taku0521

2017/05/30 09:09

ご回答ありがとうございます。 AND条件で検索すると$conditionsが、OR条件で検索すると$conditions2が作成され、 $conditionsが1つ、$conditions2が2つ存在する時に、 if (!empty($conditions) and !empty($conditions2)) { $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' AND ' . '(' . implode(' OR ', $conditions2) . ')'; } により、AND A,OR B,OR Cが? AND (? OR ?)になります。 ORについてですが、ユーザーが入力した順にORキーワードを$conditions2に格納し、implodeで結合するというイメージです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問