- ベストアンサー
SQL文の書き方をご教授 | 分かりやすい解説あり
- SQL文の書き方についてご教授いたします。質問者様は、複数のチェックボックスで絞り込み検索を実装したいとのことですが、現在のSQL文に問題があり、二つ目の選択肢で絞り込めない状況にあるようです。こちらでは、正しいSQL文の書き方や絞り込み方法について詳しく解説いたします。
- まず、現在のSQL文の問題点を確認しましょう。二つ目の選択肢を絞り込むためには、OR条件を用いる必要がありますが、現在のSQL文ではAND条件が重複してしまっているため、絞り込めない状況になっています。次に、正しいSQL文の書き方として、絞り込み条件をOR条件で結合する方法をご紹介いたします。
- 絞り込み条件をOR条件で結合するためには、IN演算子を使用する方法があります。例えば、kidが1または2の場合を絞り込む場合、以下のようなSQL文を記述します。 SELECT * FROM テーブル名 WHERE kid IN (1, 2);
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
あ・・・$rowsの宣言がされてないですね while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $rows[]=$row; }; の直前に $rows=array(); としといた方がいいかもしれません。
その他の回答 (4)
- yambejp
- ベストアンサー率51% (3827/7415)
>Warning: Invalid argument supplied for foreach() in に表示される行番号って foreach( $rows as $row ){ のところですか? $rowsが配列じゃない文字列や数値の時にでるエラーですね とりあえず foreach((array) $rows as $row ){ とすれば、なおるような気もしますが、 なぜここで$rowsが配列でなくなっているのかちょっとわかりません。 なにかタイプミスがあるのでしょうか?
- yambejp
- ベストアンサー率51% (3827/7415)
じゃ、こんな感じで・・・ カラムの名称などは適当にあわせてください <?PHP //初期設定 //username,$password,$dbnameは適当に $dsn = 'mysql:host=localhost; dbname='.$dbname; $data=array(); $sql = "SELECT t1.* FROM t_hotels as t1 "; $flag=true; //kid絞り込み if(isset($_REQUEST["kid"]) and is_array($_REQUEST["kid"])){ $sql.="INNER JOIN (SELECT DISTINCT hid FROM t_hotel_kodawari WHERE kid in ("; $sql.=implode(",",array_fill(0,count($_REQUEST["kid"]), '?')); $sql.=")) as t2 ON t1.id=t2.hid "; $data=array_merge($data,$_REQUEST["kid"]); $flag=false; } //WHERE句作成 $sql.= "WHERE 1 "; //住所絞り込み if(isset($_REQUEST["address"]) and $_REQUEST["address"]!==""){ $sql.="AND address LIKE ? "; array_push($data,"%".$_REQUEST["address"]."%"); $flag=false; } //価格絞り込み if(isset($_REQUEST["price_min"]) and $_REQUEST["price_min"]!==""){ $price_min=str_replace(",","",$_REQUEST["price_min"]); }else{ $price_min=0; } if(isset($_REQUEST["price_max"]) and $_REQUEST["price_max"]!==""){ $price_max=str_replace(",","",$_REQUEST["price_max"]); }else{ $price_max=1000000; } if(isset($_REQUEST["price_min"]) or isset($_REQUEST["price_max"])){ $sql.="AND price BETWEEN ? AND ? "; array_push($data,$price_min,$price_max); $flag=false; } //なにもパラメータがないときは表示しない if($flag) $sql.="AND 0 ";; //参考 print $sql."<br>"; print_r($data); //実行 $pdo = new PDO($dsn,$username,$password); $stmt = $pdo->prepare( $sql); $stmt->execute($data); while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $rows[]=$row; }; print_r($rows);
補足
いつも教えていただき本当に感謝いたします。 あともう一息でできるのではと思っています。 ありがとうございます。 もしうまくいったらお礼をしたいくらいです。 まさかここまで教えてもらえるとは思ってもいませんでした。 いつも素人の質問でもうしわけありませんが、 このようなエラーが出てしまいます。 配列の出し方が問題だと思うのですが、どのようにプログラムを書けばいいのかわかりません。 一部前半の部分を省略したコードをさらしますので、 どう書けば良いのか教えていただきたいです。 ただ教えてくれるかどうかは全然自由なのでスルーしてもらっても大丈夫です。 Warning: Invalid argument supplied for foreach() in <body id="S03-10"> <div id="main"> <h1>ビジネスホテルの条件検索</h1> <form name="search_form" action="xxxxx.php" method="post" > <input type="hidden" name="cmd" value="search" /> <table> <tr> <th>物件種別</th> <td> <input type="checkbox" name="kid[]" value="1" <?php if( $_REQUEST["kid"] == "1" ){ print( 'checked' ); } ?>/> 温泉 <input type="checkbox" name="kid[]" value="2" <?php if( $_REQUEST["kid"] == "2" ){ print( 'checked' ); } ?>/> キャンペーン <input type="checkbox" name="kid[]" value="3" <?php if( $_REQUEST["kid"] == "3" ){ print( 'checked' ); } ?>/> イベント <input type="checkbox" name="kid[]" value="4" <?php if( $_REQUEST["kid"] == "4" ){ print( 'checked' ); } ?>/> 特別室<br /> <input type="checkbox" name="kid[]" value="5" <?php if( $_REQUEST["kid"] == "5" ){ print( 'checked' ); } ?>/> 和室 <input type="checkbox" name="kid[]" value="6" <?php if( $_REQUEST["kid"] == "6" ){ print( 'checked' ); } ?>/> 喫煙室</td> </tr> <tr> <th>価格帯</th> <td> <input type="text" name="price_min" value="<?php print( htmlspecialchars( $_REQUEST["price_min"] ,ENT_QUOTES ) ) ?>" size="8"> ~ <input type="text" name="price_max" value="<?php print( htmlspecialchars( $_REQUEST["price_max"] ,ENT_QUOTES ) ) ?>" size="8"><br /> </td> </tr> <tr> <th>住所</th> <td><input type="text" name="address" value="<?php print( htmlspecialchars( $_REQUEST["address"] ,ENT_QUOTES ) ) ?>" size="20"></td> </tr> </table> <input type="submit" value="検索" class="Btn-gray button"> </form> <p> </p> <?php //初期設定 //username,$password,$dbnameは適当に if( $_REQUEST["cmd"] == "search" ){ $dsn = 'mysql:host=localhost;dbname=hotel_reservation'; $username = 'root'; $password = 'xxxxxx'; $data=array(); $sql = "SELECT t1.* FROM t_hotels as t1 "; $flag=true; //kid絞り込み if(isset($_REQUEST["kid"]) and is_array($_REQUEST["kid"])){ $sql.="INNER JOIN (SELECT DISTINCT hid FROM t_hotel_kodawari WHERE kid in ("; $sql.=implode(",",array_fill(0,count($_REQUEST["kid"]), '?')); $sql.=")) as t2 ON t1.id=t2.hid "; $data=array_merge($data,$_REQUEST["kid"]); $flag=false; } //WHERE句作成 $sql.= "WHERE 1 "; //住所絞込み if(isset($_REQUEST["address"]) and $_REQUEST["address"]!==""){ $sql.="AND address LIKE ? "; array_push($data, "%" .$_REQUEST["address"]."%"); $flag=false; } //価格絞り込み if(isset($_REQUEST["price_min"]) and $_REQUEST["price_min"]!==""){ $price_min=str_replace(",","",$_REQUEST["price_min"]); }else{ $price_min=0; } if(isset($_REQUEST["price_max"]) and $_REQUEST["price_max"]!==""){ $price_max=str_replace(",","",$_REQUEST["price_max"]); }else{ $price_max=1000000; } if(isset($_REQUEST["price_min"]) or isset($_REQUEST["price_max"])){ $sql.="AND price BETWEEN ? AND ? "; array_push($data,$price_min,$price_max); $flag=false; } //なにもパラメータがないときは表示しない if($flag) $sql.="AND 0 ";; //参考 print $sql."<br>"; print_r($data); //実行 $pdo = new PDO($dsn,$username,$password); $stmt = $pdo->prepare($sql); $stmt->execute($data); while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $rows[]=$row; }; print_r($rows); ?> <table border="1"> <caption>検索結果</caption> <tr> <th></th> <th>ホテル名</th> <th>宿泊料金</th> <th>住所</th> </tr> <?php foreach( $rows as $row ){ ?> <tr> <td><img src="hotel/<?php print( htmlspecialchars( $result["id"], ENT_QUOTES )); ?>.png" /></td> <td><?php print( htmlspecialchars( $result["hotel_name"], ENT_QUOTES )); ?></td> <td>\<?php print( htmlspecialchars( number_format( $result["price_min"] ),ENT_QUOTES ) ); ?></td> <td> <?php print( htmlspecialchars( $result["address"], ENT_QUOTES ) ); ?> </td> </tr> <?php } } ?> </table> </div> </body> </html>
- yambejp
- ベストアンサー率51% (3827/7415)
たとえばこんな感じ SELECT t1.* FROM t_hotels as t1 INNER JOIN (SELECT hid FROM t_hotel_kodawari WHERE kid in (1,3,4)) as t2 ON t1.id=t2.hid t_hotel_kodawariをkidの値で絞り込んでからINNER JOINするとよいでしょう PHPの処理的には $sql="SELECT t1.* FROM t_hotels as t1 "; if(isset($_REQUEST["kid"]) and is_array($_REQUEST["kid"])){ $sql.="INNER JOIN (SELECT hid FROM t_hotel_kodawari WHERE kid in (" $sql.=implode(",",array_fill(0,count($_REQUEST["kid"]), '?')) $sql.=") as t2 ON t1.id=t2.hid "; } のようにSQL文をつくっておき、あとからkidの値を?に当てはめればいいでしょう
補足
yambejp様、いつもご教授くださり大変感謝しております。ありがとうございます。 kidの部分まで絞り込んで値を入れていくSQL文はわかりませんでした。 私の読んでいる本には書いていないことばかりで理解することがかなり難しいです。 わたしにもっと理解力があればといつも思います。 Parse error: syntax error, unexpected '$sql' (T_VARIABLE) inという表示が出てしまいます。 原因がどこにあるのか力不足でわからない状態です。 私なりに考えたのですが、$conditionに何も無いからかもしれません。 もし別の原因で間違っていたら申し訳ありません。 もしよろしければ $condition[$tmpKey] = $_REQUEST["kid"][$i]; だとか if( !empty( $_REQUEST["address"] ) ){ $sql = $sql . " and ( address like :address ) "; $condition[":address"] = "%{$_REQUEST["address"]}%"; } というような感じで $conditionに値(プレースホルダでしょうか?)を入れるみたいなプログラムの書き方を教えてもらえないでしょうか? いつも申し訳ありません。 念のため他の受け手の方のプログラムさらしておきます。 今回も勉強させていただき、ありがとうございました。 if( !empty( $_REQUEST["price_min"] ) ){ $sql = $sql . " and price >= :price_min " ; $condition[":price_min"] = $_REQUEST["price_min"]; var_dump($sql); } if( !empty( $_REQUEST["price_max"] ) ){ $sql = $sql . " and price <= :price_max "; $condition[":price_max"] = $_REQUEST["price_max"]; } if( !empty( $_REQUEST["address"] ) ){ $sql = $sql . " and ( address like :address ) "; $condition[":address"] = "%{$_REQUEST["address"]}%"; } $statement = $pdo->prepare( $sql ); $statement->execute( $condition ); $results = $statement->fetchAll();
- t_ohta
- ベストアンサー率38% (5241/13712)
$sql .= " and kid = :".$tmpKey; を $sql .= " or kid = :".$tmpKey; にするだけでは?
お礼
t_ohta様、今回もアドバイス感謝いたします。 誠にありがとうございます。 orに変更したのですが、重複して表示されていて上からAホテルが3つ、Bホテル2つが、Cは1つ、 Dが2つ、Eが2つ、Fが1、Gが1つ縦に並んだ状態になってしまいます。 重複表示しないようにしたいのですが、なかなかうまくいきません。 HTMLの表示のさせかたか、MySQL並べ方が良くないのでしょうか?要因はどこにあるかわからない状態です。 質問ばかりで申し訳ありません。
お礼
出力できない理由がわかりました! 単純なミスでした。$rowで出力しなければならないのが$resultになっていました! お騒がせいたしました。 yambejp様には本当になんて言っていいのかわからないくらい感謝しております! 今回のような検索機能は実装できたのがはじめてなので、感無量です! 長きに渡って疑問がようやく解決されました。 yambejp様、そして他の方々も私のような素人の相談に乗っていただき本当にありがとうございました!
補足
まさに foreach((array) $rows as $row ){ にして$rows=array();も表記したら エラーが消えました。 エラーの行番号もyambejp様の仰る通りでした。 あと検索結果が項目意外、表示されないです。 カラムが合ってないのでしょうか? t_hotels id hotel_name price_min price_max address 1 HOTELA 10000 15000 栃木県・・・ 2 HOTELB 12000 20000 栃木県・・・ 3 HOTELC 9000 18000 千葉県・・・ 4 HOTELD 20000 25000 千葉県・・・ 5 HOTELE 15000 30000 愛知県・・・ 6 HOTELF 30000 35000 東京都・・・ 7 HOTELG 40000 43000 神奈川県・・・ t_hotel_kodawari hid kid 1 1 1 3 1 4 2 1 2 5 3 2 4 3 4 6 5 2 5 3 6 1 7 2 合ってると思うのですが。 以下、print_rの返す内容です。 SELECT t1.* FROM t_hotels as t1 INNER JOIN (SELECT DISTINCT hid FROM t_hotel_kodawari WHERE kid in (?,?)) as t2 ON t1.id=t2.hid WHERE 1 AND address LIKE ? AND price BETWEEN ? AND ? Array ( [0] => 1 [1] => 5 [2] => %千葉県% [3] => 6000 [4] => 10000 ) Array ( ) 原因は何が考えられますでしょうか? 何卒よろしくお願い致します。