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

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

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

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

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

PHP

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

Q&A

解決済

4回答

3376閲覧

MYSQLで複数のパターンのquery-selectを準備する場合

SugiuraY

総合スコア317

MySQL

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

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

PHP

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

0グッド

0クリップ

投稿2017/05/16 09:10

編集2017/05/16 09:13

入力フォームから複数の情報が選択され、その選択肢に応じてmysqlから情報を取得する一般的な状況です。

例えば以下のような選択肢がある場合、
q1はチェック入力必須として、q2、q3が任意とします。
とすると以下のように3パターンの条件でデータを抽出することが考えられます。
1.q1
2.q1 + q2
2.q1 + q3

HTML

1<div id="q1">q1</div> 2 <input type="checkbox" name="a[]" value="1">1 3 <input type="checkbox" name="a[]" value="2" >2 4 5<div id="q2">q2</div> 6 <input type="checkbox" name="b[]" value="1">1 7 <input type="checkbox" name="b[]" value="2" >2 8 9<div id="q3">q3</div> 10 <input type="checkbox" name="c[]" value="1">1 11 <input type="checkbox" name="c[]" value="2" >2 12

実際には、入力項目が多いため、もっと多くのパターンがありえるのですが、
実務的にこのような場合、php & MYSQL (PDO)上
switchのような形で分岐させてそれぞれのswitch内の処理でwhereの条件を変えていくべきなのでしょうか?
未だ不慣れな私にはこのような方法しか思い浮かびません。。(下記の例をご覧ください)
そうなるとかなりのパターンがあるので、適切ではないかとも考えています。
このような処理で実務的、一般的なものがあればアドバイスを頂ければ幸いです。

以下は上記のswitchイメージになります。

PHP

1 2try { 3switch (XXX){ 4case 1: 5 $stmt=$pdo->prepare("SELECT XXX FROM XXX 6 where ABC = :ABC"); 7 $stmt->BindValue(':ABC',$a,PDO::PARAM_STR); 8 break; 9case 2://q1 & q2 10 $stmt=$pdo->prepare("SELECT XXX FROM XXX 11 where ABC = :ABC and DEF =:DEF"); 12 $stmt->BindValue(':ABC',$a,PDO::PARAM_STR); 13 $stmt->BindValue(':DEF',$b,PDO::PARAM_STR); 14以下省略 15161718default: 19・・ 20} 21 22$stmt->execute(); 23 $result2=$stmt->fetchall(PDO::FETCH_NUM); 24} catch (Exception $e) { 25 prep($e->getMessage()); 26}

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

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

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

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

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

guest

回答4

0

「ABC」とか「DEF」のフィールド名がどこから来ているのか不明なため、$_POST['a'] = ABC、$_POST['b'] = DEFと仮定します。

PHP

1$sql = "SELECT * FROM XXX WHERE 1=1 "; 2if(isset($_POST['a'])){ 3 $data_a = $_POST['a']; 4 $sql.= " AND ( "; 5 foreach($data_a as $key => $val){ 6 $sql.= " `ABC` = :ABC".$key." OR "; 7 } 8 $sql = rtrim($sql, ' OR '); 9 $sql.= " ) "; 10} 11if(isset($_POST['b'])){ 12 $data_b = $_POST['b']; 13 $sql.= " AND ( "; 14 foreach($data_b as $key => $val){ 15 $sql.= " `DEF` = :DEF".$key." OR "; 16 } 17 $sql = rtrim($sql, ' OR '); 18 $sql.= " ) "; 19} 20$stmt=$pdo->prepare($sql); 21if(isset($_POST['a'])){ 22 foreach($data_a as $key => $val){ 23 $stmt->bindValue(':ABC'.$key, $val, PDO::PARAM_STR); 24 } 25} 26if(isset($_POST['b'])){ 27 foreach($data_b as $key => $val){ 28 $stmt->bindValue(':DEF'.$key, $val, PDO::PARAM_STR); 29 } 30} 31$stmt->execute();

もしa=1、b=1,2がチェックされていれば

SQL

1SELECT XXX FROM XXX WHERE 1=1 AND (`ABC` = 1) AND (`DEF` = 1 OR `DEF` = 2)

というSQL文ができあがると思います。

無駄でややこしいことをしていますが、こんな感じの処理方法もありますよという例です。
速度とかエラー処理とか考えずに書いていますので、実際に利用する際はそのあたりを考えて実装してください。

投稿2017/05/16 09:42

rjunakc

総合スコア368

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

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

pegy

2017/05/16 09:49

コメント誠にありがとうございます。 ifでネスト化して分岐する例をご教示頂いたものと存じます。このように分岐処理するのがメリットがあり一般的、実務で管理がしやすいという事でしょうか? 様々な方法で処理できるとは存じますが、もしベストまたは望ましい方法であれば、そのポイントを重ねてで恐縮ですが、ご教示願いたく存じます
rjunakc

2017/05/17 04:10

あくまでも一例です。 実際のフォーム内容や選択肢により最適解は変わる可能性があります。 上記のコードの場合、チェックボックスの選択肢が運用後増えても、SQLコードは変更する必要がないという意味ではメリットがあります。 ただし、ifやforeachを多用しているため、コード的に美しくはないですし、速度的にもメリットがあるとは思えません。(数百万レコードくらいないと速度的なデメリットは感じにくいでしょうが)
SugiuraY

2017/05/17 08:23

承知を致しました、コメント頂き誠にありがとうございます。
guest

0

ベストアンサー

こんな感じでしょうかね

PHP

1<form method="get"> 2<div id="q1">q1</div> 3<input type="checkbox" name="a[]" value="1">1 4<input type="checkbox" name="a[]" value="2" >2 5<div id="q2">q2</div> 6<input type="checkbox" name="b[]" value="1">1 7<input type="checkbox" name="b[]" value="2" >2 8<div id="q3">q3</div> 9<input type="checkbox" name="c[]" value="1">1 10<input type="checkbox" name="c[]" value="2" >2 11<input type="submit" value="go"> 12</form> 13<?PHP 14 15$a=filter_input(INPUT_GET,'a',FILTER_VALIDATE_INT,["flags"=>FILTER_REQUIRE_ARRAY]); 16$b=filter_input(INPUT_GET,'b',FILTER_VALIDATE_INT,["flags"=>FILTER_REQUIRE_ARRAY]); 17$c=filter_input(INPUT_GET,'c',FILTER_VALIDATE_INT,["flags"=>FILTER_REQUIRE_ARRAY]); 18 19$sql = 'SELECT XXX FROM XXX WHERE 1 '; 20$data=[]; 21 22if(count($a)>0){ 23$data=array_merge($data,$a); 24$sql.="AND ABC IN(".implode(",",array_fill(0,count($a),"?")).") "; 25} 26if(count($b)>0){ 27$data=array_merge($data,$b); 28$sql.="AND DEF IN(".implode(",",array_fill(0,count($b),"?")).") "; 29} 30if(count($c)>0){ 31$data=array_merge($data,$c); 32$sql.="AND GHI IN(".implode(",",array_fill(0,count($c),"?")).") "; 33} 34print $sql; 35/* 事前に$pdoは定義しておく*/ 36$stmt = $pdo->prepare( $sql); 37$stmt->execute($data); 38 39?>

投稿2017/05/16 11:58

yambejp

総合スコア114839

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

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

SugiuraY

2017/05/17 08:21

なるほど、条件を設定して満たせばwhere句に条件を結合していくのですね。 目からうろこでした。大変勉強になります。 是非採用させて頂きます。宜しくお願いいたします。
guest

0

任意のところは入力があったら文字連結させていくのはどうでしょうか?

サンプルはname="a[]"としてるので、実際には、$_POST['a'][0]に入りますが、
ややこしいので$_POST['a']にしておきます。

php

1//POSTで検索条件を受け取る 2$a = $_POST['a']; 3$b = $_POST['b']; 4 5$sql = 'SELECT XXX FROM XXX WHERE'; 6//$aは必須入力だからifいれない 7 $sql .= ' abc = :abc'; 8//$bは任意入力 9if(!empty($b)) { 10$sql .= ' AND def LIKE :def'; 11} 12$stmt = $pdo -> prepare($sql); 13//プリペアドステートメントを実行する(インジェクション対策) 14$stmt -> bindValue(':abc', $a, PDO::PARAM_STR); 15if(!empty($b)) { 16$stmt -> bindValue(':def', '%'.$b.'%', PDO::PARAM_STR); 17} 18$stmt -> execute($sql);

投稿2017/05/16 10:06

編集2017/05/16 10:12
mirainonakamura

総合スコア137

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

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

KiyoshiMotoki

2017/05/16 10:24 編集

$_POST['b'] はチェックボックスの値、すなわち配列なので、  $stmt -> bindValue(':def', '%'.$b.'%', PDO::PARAM_STR); 部分は "%Array%" という文字列をバインドしていることになりますよ。 http://php.net/manual/ja/language.types.string.php#language.types.string.casting > 配列は常に "Array" という文字列に変換されるので、(以下略) $_POST['a'] も、同様ですね。
SugiuraY

2017/05/17 08:22

コメント有難うございます、 上記の通り文字連結の発想がなかったため、大変勉強になりました。 早速取り組んでみたいと思います。
guest

0

もしくは、$a, $bのデフォルト値を決めて1個のクエリにしてしまうか。

PHP

1$sql = 'SELECT XXX FROM XXX (''=:ABC OR ABC=:ABC) and (''=:DEF OR DEF=:DEF)'; 2$stmt = $pdo -> prepare($sql); 3$stmt->BindValue(':ABC',$a,PDO::PARAM_STR); 4$stmt->BindValue(':DEF',$b,PDO::PARAM_STR);

投稿2017/05/17 03:46

haru666

総合スコア1591

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

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

SugiuraY

2017/05/17 08:26

コメント有難うございます。 正直に申しあげて未だ不慣れで分からない部分があったのですが、全パターンをandでつないでいくということでしょうか?またデフォルト値を決めるというのは具体的にどのようなことでしょうか? 度々恐れ入り増すが宜しくお願い申し上げます。
haru666

2017/05/17 08:41

例えば、整数のマスタ値なんかだと分かりやすいですが、マスタ値が1から始まるなら0を未設定としてクエリを構築します。そうすると、パラメータが0の場合はtrue、それ以外の場合、カラムが一致しているか判定、というコードを組むことができます。 (0=:Param OR Param=:Param) これを数珠繋ぎにすることで複数条件のON/OFFを1クエリ上で実現できます。 (クエリオプティマイザでよくよく検証する必要はありますけどね!) 文字列検索の場合でも、文句が設定されていればフィルタ、空なら無視、という条件を、1クエリ上で実現できます。空とnullの違いには気を付ける必要があると思いますが、こういう書き方をするとPHP側のコードはかなりシンプルになります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問