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

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

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

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

2回答

2980閲覧

データベース 絞り込み PHP 1対多のテーブルの多に対して複数の条件がある

001KEN001

総合スコア10

PDO

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

1クリップ

投稿2019/01/18 14:31

前提・実現したいこと

PHPとMySQLを使って学校の全生徒の名簿をデータベースにしてチェックボックスを用いて絞り込む機能を実現したいです。
チェックボックスに何も入力がない場合は全てのデータを出力するようにしています。
チェックボックスに入力がある場合はsql文に必要な条件をつけ足して絞り込むつもりです。
最終的に家族構成や性格などの入力も同時に受け付けて絞り込めるようにしたいと思っています。

以上を踏まえて、以下の様なデータベースが与えられたとき、部活番号001に所属している人かつ部活番号002に所属している人のデータを取り出したいです。

####データベースは以下の通りです(問題の個所に対応する部分だけです)。
|学籍番号|氏名|性別|学年|住所|備考|
|:--|:--:|--:|
|001|鈴木太郎|男|1|東京|無し|
|002|田中太郎|男|2|埼玉|無し|
|003|鈴木花子|女|3|東京|無し|
|004|田中花子|女|1|千葉|無し|

学生番号部活番号
001001
001002
001003
002001
002003
003002
004001
004002

####望む結果

学籍番号列2
001
004

####現状

学籍番号列2
001
002
003
004

※データベースのテーマは変えています。実際は食材のデータを扱いますがカラム名が伝わりにくいと思ったので想像しやすいテーマにしました。

全体のソースコード

php

1<?php 2 $kazoku_arr = array('弟', '妹', '兄', '姉', '父', '母', 'ペット'); 3 $seikaku_arr = array('熱', '温', '平', '涼', '寒'); 4 $bukatu_arr = array('陸上', 'バスケ', 'サッカー','茶道', '書道', '文学', '囲碁','美術','バレー','テニス'); 5 $classification_arr = array('男', '女'); 6 7 //inputbox作成用の関数 8 function array2inputbox($type, $arr, $name){ 9 if($type === "single"){ 10 for ($i = 0; $i < count($arr); $i++) { 11 $s = $i+1; 12 echo "<input type='radio' name='$name' value='$s'>{$arr[$i]}\n"; 13 } 14 }else if($type === "multi"){ 15 for ($i = 0; $i < count($arr); $i++) { 16 $s = $i+1; 17 echo "<input type='checkbox' name='", $name, "[]' value='$s'>{$arr[$i]}\n"; 18 } 19 } 20 } 21 22 try { 23 24 // リクエストから得たスーパーグローバル変数をチェックするなどの処理 25 //nameとseikakuとclassificationは単一情報 26 if(isset($_GET['name']) && $_GET['name']!=''){ 27 $name = htmlspecialchars($_GET['name']); 28 }else{ 29 $name = NULL; 30 } 31 if(isset($_GET['seikaku']) && $_GET['seikaku']!=''){ 32 $seikaku = htmlspecialchars($_GET['seikaku']); 33 }else{ 34 $seikaku = NULL; 35 } 36 if(isset($_GET['classification']) && $_GET['classification']!=''){ 37 $classification = htmlspecialchars($_GET['classification']); 38 }else{ 39 $classification = NULL; 40 } 41 //kazokuとbukatuは配列の可能性あり 42 if(isset($_GET['kazoku']) && is_array($_GET['kazoku'])){ 43 $kazoku = $_GET['kazoku']; 44 }else{ 45 $kazoku = NULL; 46 } 47 48 if(isset($_GET['bukatu']) && is_array($_GET['bukatu'])){ 49 $bukatu = $_GET['bukatu']; 50 }else{ 51 $bukatu = NULL; 52 } 53 54 //新型 55 56 // データベースに接続 57 $pdo = new PDO( 58 'mysql:dbname=db;host=127.0.0.1;charset=utf8', 59 'ken', 60 '001', 61 [ 62 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 63 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, 64 ] 65 ); 66 67 //何も選択されていない場合は全てを取得して表示 68 if($name===NULL && $kazoku===NULL && $seikaku===NULL && $bukatu===NULL && $classification===NULL){ 69 //全データ表示のためのクエリ 70 $que_all = 'SELECT * FROM main'; 71 //PDOStatement 72 $stmt = $pdo->query($que_all); 73 } else { 74 //ベースとなるクエリ 75 $que_search = 'SELECT DISTINCT main.* FROM main, has_kazoku, has_bukatus WHERE has_bukatus.name_id = main.name_id AND has_kazoku.name_id = main.name_id '; 76 77 //seikakuのチェック情報からクエリに条件を追加 78 if($seikaku != NULL){ 79 $que_search .= ' AND main.shisei_id =' . $seikaku; 80 } 81 82 //classificationのチェック情報からクエリに条件を追加 83 if($classification != NULL){ 84 $que_search .= ' AND main.classification_id =' . $classification; 85 } 86 87 //kazokuのチェック情報からクエリに条件を追加 88 if($kazoku != NULL){ 89 $que_kazoku = ' '; 90 for($i=0;$i<count($kazoku);$i++){ 91 if($i===0){ 92 $que_kazoku .= '&& ('; 93 $que_kazoku .= 'has_kazoku.kazoku_id =' . $kazoku[$i]; 94 } 95 $que_kazoku .= ' OR has_kazoku.kazoku_id =' . $kazoku[$i]; 96 } 97 98 $que_search .= $que_kazoku. ')'; 99 100 } 101 102 //完成したクエリをpdostatementに 103 $stmt = $pdo->query($que_search); 104 } 105 106 107 } catch (PDOException $e) { 108 109 // エラーが発生した場合は「500 Internal Server Error」でテキストとして表示して終了する 110 // - もし手抜きしたくない場合は普通にHTMLの表示を継続する 111 // - ここではエラー内容を表示しているが, 実際の商用環境ではログファイルに記録して, Webブラウザには出さないほうが望ましい 112 header('Content-Type: text/plain; charset=UTF-8', true, 500); 113 exit($e->getMessage()); 114 115 } 116 117 // Webブラウザにこれから表示するものがUTF-8で書かれたHTMLであることを伝える 118 // (これか <meta charset="utf-8"> の最低限どちらか1つがあればいい. 両方あっても良い.) 119 //header('Content-Type: text/html; charset=utf-8'); 120 121?> 122<!DOCTYPE html> 123<html lang="ja"> 124 <head> 125 <meta charset="utf-8"> 126 <title>データベース</title> 127 <meta name="viewport" content="width=device-width"> 128 <link rel="stylesheet" href="style.css"> 129 </head> 130 <body> 131 <div class="search-form"> 132 <form method="get" action="index.php" enctype="multipart/form-data"> 133 <table border=0> 134 <!--名前--> 135 <tr> 136 <td>名前:</td> 137 <td><input name="name" size="20"></td> 138 </tr> 139 <!--性別--> 140 <tr> 141 <td>性別:</td> 142 <td> 143 <?php 144 array2inputbox("single", $classification_arr, "classification"); 145 ?> 146 </td> 147 </tr> 148 <!--家族構成--> 149 <tr> 150 <td>家族構成:</td> 151 <td> 152 <?php 153 array2inputbox("multi", $kazoku_arr, "kazoku"); 154 ?> 155 </td> 156 </tr> 157 <!--性格--> 158 <tr> 159 <td>性格:</td> 160 <td> 161 <?php 162 array2inputbox("single", $seikaku_arr, "seikaku"); 163 ?> 164 </td> 165 </tr> 166 <!--部活--> 167 <tr> 168 <td>部活:</td> 169 <td> 170 <?php 171 array2inputbox("multi", $bukatu_arr, "bukatu"); 172 ?> 173 </td> 174 </tr> 175 <tr> 176 <td><input type="submit" value="検索"></td> 177 </tr> 178 </table> 179 </form> 180 </div> 181 <br><BR> 182 <div class="result-table"> 183 <table class="table2" border=0> 184 <tr><th align='center'>食材名</th><th align='center'>家族構成</th><th align='center'>性格</th><th align='center'>部活</th><th align='center'>備考</th></tr> 185 <?php 186 //tableとして代入するための文字列を別ファイルから読み込み 187 $base = file_get_contents('base.html'); 188 189 //新型 190 //http://php.net/manual/ja/pdostatement.fetch.phpを参照 191 while ($row = $stmt->fetch()){ 192 //家族構成のデータをdb->has_kazoku.name_id と db->main.name_id と照らし合わせて取得(複数個あることを留意) 193 //その後 db->has_kazoku.kazoku_id と db->kazoku_names.kazoku_id と照らし合わせて文字に変換 194 $kazoku_stmt = $pdo->prepare('SELECT DISTINCT kazoku_name FROM main, has_kazoku, kazoku_names WHERE has_kazoku.name_id = :name_id AND kazoku_names.kazoku_id = has_kazoku.kazoku_id'); 195 $kazoku_stmt->execute([':name_id'=>$row['name_id']]); 196 ////家族構成のデータを連結させて一つの文字列に 197 $kazoku_results = ''; 198 while ($oneOfkazoku = $kazoku_stmt->fetch()) { 199 $kazoku_results .= $oneOfkazoku['kazoku_name'].' '; 200 } 201 202 //部活のデータをdb->has_bukatus.name_id と db->main.name_id と照らし合わせて取得(複数個あることを留意) 203 //その後 db->has_bukatus.bukatu_id と db->bukatu_names.bukatu_id と照らし合わせて文字に変換 204 $bukatu_stmt = $pdo->prepare('SELECT DISTINCT bukatu_name FROM main, has_bukatus, bukatu_names WHERE has_bukatus.name_id = :name_id AND bukatu_names.bukatu_id = has_bukatus.bukatu_id'); 205 $bukatu_stmt->execute([':name_id'=>$row['name_id']]); 206 ////家族構成のデータを連結させて一つの文字列に 207 $bukatu_results = ''; 208 while ($oneOfbukatu = $bukatu_stmt->fetch()) { 209 $bukatu_results .= $oneOfbukatu['bukatu_name'].' '; 210 } 211 212 //$row['seikaku_id'] を db->seikaku_names->seikaku_name と適合させて代入 213 $seikaku_stmt = $pdo->prepare('SELECT seikaku_name FROM main, seikaku_names WHERE seikaku_names.seikaku_id = :seikaku_id'); 214 $seikaku_stmt->execute([':seikaku_id'=>$row['shisei_id']]); 215 $seikaku_result = $seikaku_stmt->fetch(); 216 217 //$baseへの値の代入 218 printf($base, $row['link_page'], htmlspecialchars($row['name']), $kazoku_results, $seikaku_result['seikaku_name'], $bukatu_results, htmlspecialchars($row['kounou'])); 219 } 220 ?> 221 </table> 222 </div> 223 </body> 224</html> 225

html

1<!--base.html--> 2<tr><td align='center'><a href="%s">%s</a></td><td align='center'>%s</td><td align='center'>%s</td><td align='center'>%s</td><td align='center'>%s</td></tr>

### 該当部分

php

1//kazokuのチェック情報からクエリに条件を追加 2 if($kazoku != NULL){ 3 $que_kazoku = ' '; 4 for($i=0;$i<count($kazoku);$i++){ 5 if($i===0){ 6 $que_kazoku .= '&& ('; 7 $que_kazoku .= 'has_kazoku.kazoku_id =' . $kazoku[$i]; 8 } 9 $que_kazoku .= ' OR has_kazoku.kazoku_id =' . $kazoku[$i]; 10 } 11 12 $que_search .= $que_kazoku. ')'; 13 14 } 15

試したこと

どうしても思いつかないのでOR検索になるようにしています。

ここに問題に対して試したことを記載してください。

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

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

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

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

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

guest

回答2

0

あまり良いやり方ではありませんが、一番簡単なのを書きます。

テーブル名がないので、二つ目のテーブルを部活リストとすると

sql

1SELECT 生徒番号 2FROM 部活リスト 3WHERE 部活番号 IN (001,002) 4GROUP BY 生徒番号 5HAVING COUNT(*) = 2 -- 選択した部活番号の個数

投稿2019/01/20 04:42

kantomi

総合スコア295

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

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

kantomi

2019/01/20 04:46

生徒マスタ(メニューマスタ、食材マスタかな?)は、上記のSQLをサブクエリにして、そのサブクエリに対して JOIN すれば良いでしょう。
001KEN001

2019/01/21 03:20

返答ありがとうございます。大変参考になりました。SQLサーバー上では望む結果を得られるようになったのでphpで今から実装します。一つ気になったのですが、「あまり良いやり方ではありませんが…」と書かれていらっしゃいますが、どのあたりがあまり良くないのでしょうか。教えていただきたいです。
kantomi

2019/01/22 02:36

選択した個数を別建てで設定するのは、あまりSQL的とは言えません。 再帰SQLでできますが、MySQLの再帰クエリは、8.0.3 からの機能なので控えました。
guest

0

活番号001に所属している人かつ部活番号002に所属している人のデータを取り出したいです。
とのことでしたが、コードは、家族での条件になっています。
部活の条件が見当たらない気がします。
OR以外には、IN句を使用することもできます。 bukatu_id IN (チェックしたID1,チェックしたID2)

投稿2019/01/18 19:55

sweeper

総合スコア16

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

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

001KEN001

2019/01/19 04:43

返答ありがとうございます。本当ですね。変数名を家族にしてしまっています。kazokuもbukatuも変数名が違うこと以外は全く同じ処理を行うことを考えておりますので、kazokuと書かれている部分はbukatuと置き換えていただいて差し支えないです。 IN句は引数を含むデータを返すという理解なのですが、それを使って望む結果(001,004)を出力することができなかったのですが、何か方法があるのですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問