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

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

ただいまの
回答率

90.51%

  • PHP

    24001questions

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

  • MySQL

    6989questions

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

絞り込み検索 複数 データベース

解決済

回答 4

投稿

  • 評価
  • クリップ 2
  • VIEW 3,881

magument

score 8

 前提・実現したいこと

質問が2つあります。どちらか片方でも答えてくれたら助かります。

PHPとMySQLをつかって、学生登録システムを作っています。

質問1
ーーーーーーーーーーーーーーーーーーーー
条件を入力し、学生の絞り込みをしたいのですが、条件を複数選択した場合うまくいきません。
条件を性別だけ、所属だけ、と単独なら正常処理します。
例、性別→女、所属→文化部、で検索すると花子文化部、のび太文化部が表示されてしまう。

今のプログラムでは所属のif分が最後にあり、所属が優先されるプログラムです。
どうやったら、条件を複数選択しても、正しく絞り込みができるでしょうか?
ーーーーーーーーーーーーーーーーーーーー

質問2
ーーーーーーーーーーーーーーーーーーーー
「運動部」で検索しても、yaruo運動部、一人しか検索されません。
正しい処理は
ruck    ruck@    女    運動部,帰宅部,生徒会,
yaruo    aaa@    男    運動部
yaruo    aaa@    男    運動部生徒会
出木杉    aaa@    男    運動部文化部生徒会
4人検索されるはずです。
この問題の解決方法はどうすればいいでしょうか?
質問2は大幅にプログラムとテーブルを書き換えないと駄目ですね( ;∀;)
ーーーーーーーーーーーーーーーーーーーー
ここに質問の内容を詳しく書いてください。(例)PHP(CakePHP)で●●なシステムを作っています。
■■な機能を実装中に以下のエラーメッセージが発生しました。

 該当のソースコード

<!-- 学生表示画面 -->
<!-- list.php -->

<?php

$res = "";  //新しいウェブページのエラー回避

$USER= 'root';
$PW= '1234';
$DBINFO= "mysql:dbname=cwdb;host=localhost;charset=utf8";

try{
    $pdo = new PDO($DBINFO,$USER,$PW); //pdoインスタンスの生成
    $sql = "SELECT * FROM students";

    //$sql = "SELECT * FROM students WHERE student_name LIKE '%山%'";
    if (isset($_POST['freeword'])) {
        $sql = "SELECT * FROM students WHERE student_number LIKE '%{$_POST['freeword']}%' OR student_name LIKE '%{$_POST['freeword']}%' OR email LIKE '%{$_POST['freeword']}%' ";
    }

    if (isset($_POST['sex'])) {
        if ($_POST['sex'] == "男") {
            $sql = "SELECT * FROM students WHERE sex = '男'";
        }elseif ($_POST['sex'] == "女") {
            $sql = "SELECT * FROM students WHERE sex = '女'";
        }
    }

    if (isset($_POST['syozoku'])) {
        if ($_POST['syozoku'] == "運動部") {
            $sql = "SELECT * FROM students WHERE syozoku = '運動部'";
        }elseif ($_POST['syozoku'] == "文化部") {
            $sql = "SELECT * FROM students WHERE syozoku = '文化部'";
        }elseif ($_POST['syozoku'] == "帰宅部") {
            $sql = "SELECT * FROM students WHERE syozoku = '帰宅部'";
        }elseif ($_POST['syozoku'] == "生徒会") {
            $sql = "SELECT * FROM students WHERE syozoku = '生徒会'";
        }
    }

   $stmt = $pdo->prepare($sql);
    $stmt->execute(null);
    $res = "<table border=1>
            <tr>
                <th>学籍番号</th>
                <th>氏名</th>
                <th>メールアドレス</th>
                <th>性別</th>
                <th>所属</th>
                <th>年</th>
                <th>編</th>
            </tr>\n";

    while($row = $stmt->fetch(PDO::FETCH_ASSOC)){

        $res .= <<<eod
        <tr>
            <td>{$row['student_number']}</td>
            <td>{$row['student_name']}</td>
            <td>{$row['email']}</td>
            <td>{$row['sex']}</td>
            <td>{$row['syozoku']}</td>
            <td>{$row['birth_year']}</td>
            <td><a href = "edit.php?seq={$row['seq']}">編</a></td>
        </tr>
eod;
    }

    $res .= "</table>\n";

}catch(Exception $e){
    echo "エラー発生" . $e->getMessage();
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>一覧画面</title>
</head>
<body>

<form method="post" action="regist.php">
    <input type="submit" value="新規登録"></input>
</form>

<p>
    <form method="post">
        条件を絞り込む<br>
        フリーワード<input type="text" name="freeword"><br>
        性別
        <select name="sex">
            <option></option>
            <option value="男">男</option>
            <option value="女">女</option>
        </select><br>

        所属
        <select name="syozoku">
            <option></option>
            <option value="運動部">運動部</option>
            <option value="文化部">文化部</option>
            <option value="帰宅部">帰宅部</option>
            <option value="生徒会">生徒会</option>
        </select><br>

        <input type="submit" value="検索する"></input>
    </form>
</p>

<form>
    <input type="submit" value="全員表示"> <!-- URLをクリックした時と同じ処理-->
</form><br>

<?php echo $res; ?>



</body>
</html>

イメージ説明

イメージ説明

イメージ説明

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+4

まずDBの正規化について学習して下さい
syozokuにカンマ区切りでデータを入れるのはSQLとしては非効率です
所属グループテーブルをつくり、団体ごとにidを振り
ユーザー=所属連携テーブルを別途つくって紐付けます

 sample

とりあえず今のままのデータ構成で検索するならこう

$freeword=filter_input(INPUT_POST,'freeword');
$sex=filter_input(INPUT_POST,'sex',FILTER_VALIDATE_REGEXP,["options"=>["regexp"=>"/^(男|女)$/u","default"=>NULL]]);
$syozoku=filter_input(INPUT_POST,'syozoku',FILTER_VALIDATE_REGEXP,["options"=>["regexp"=>"/^(運動部|文化部|帰宅部|生徒会)$/u","default"=>NULL]]);

$sql = "SELECT * FROM students WHERE 1 ";
$data=[];

if(!is_null($freeword) and $freeword!==""){
  $sql.= " and (0 ";
  $sql.= " or student_number LIKE ?";
  $sql.= " or student_name LIKE ?";
  $sql.= " or email LIKE ?";
  $sql.= "  ) ";
  $data=array_merge($data,array_fill(0,3,'%'.$freeword.'%'));
}

if(!is_null($sex)){
$sql.= " and sex=?";
$data[]=$sex;
}
if(!is_null($syozoku)){
$sql.= " and syozoku regexp ?";
$data[]="(^|,)".$syozoku."(,|$)";
}
print $sql."<br>";
print_r($data);

/*
検索結果の表示
$stmt = $pdo->prepare($sql);
$stmt->execute($data);
$rows=$stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);
*/
?>
<form method="post">
条件を絞り込む<br>
フリーワード<input type="text" name="freeword"><br>
性別
<select name="sex">
<option value="">---</option>
<option value="男">男</option>
<option value="女">女</option>
</select><br>
所属
<select name="syozoku">
<option value="">------</option>
<option value="運動部">運動部</option>
<option value="文化部">文化部</option>
<option value="帰宅部">帰宅部</option>
<option value="生徒会">生徒会</option>
</select><br>
<input type="submit" value="検索する"></input>
</form>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/22 16:55

    カンマ区切りだけならまだいいんですが、区切りがないのもあるし番号っぽいのもあるし、
    で、色々と改善点が多そうですよね。
    「年」の「1970」もかなり怪しいですし。

    キャンセル

+3

質問1について。

男女の別と部活の別はAND条件なので、
両方の条件が指定されているなら両方を加味したSQL(SELECT分のWHERE句)である必要があります。
SQLで得られた結果をPHP側でさらにフィルターを掛けるのはナンセンスですから。

ズバリ書くと面倒なので察してほしいのですが、私なら、
1)例えば

    $criteria = array();

    if (isset($_POST['sex'])) {
        if ($_POST['sex'] == "男") {
            $criteria[] = "sex = '男' ";  // 配列の末尾に追加
        }elseif ($_POST['sex'] == "女") {
            $criteria[] = "sex = '女' ";
        }
    }

    if (isset($_POST['syozoku'])) {
        if ($_POST['syozoku'] == "運動部") {
            $criteria[] = "syozoku LIKE '%運動部%' ";
        }elseif ($_POST['syozoku'] == "文化部") {
            $criteria[] = "syozoku LIKE '%文化部%' ";
        }elseif ($_POST['syozoku'] == "帰宅部") {
            $criteria[] = "syozoku LIKE '%帰宅部%' ";
        }elseif ($_POST['syozoku'] == "生徒会") {
            $criteria[] = "syozoku LIKE '%生徒会%' ";
        }
    }

    if (count($criteria) > 0) {
        $sql = "SELECT * FROM students WHERE " . implode('AND ', $criteria);
    }


みたいにすると、指定のあった要素がANDで結合されたSQL文が出来上がるかと。

質問2については、
人テーブルと所属テーブルの間に人1対所属多になる関連付けを示すテーブルが必要ですね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+2

pdo使っているのにbind使ってなかったり、sqlのエスケープされてなくて非常に勿体無いですね。。

入力コントロールの内容そのまま問い合わせに使うのであれば、わざわざ大量にif文使わなくて良いと思います。

質問1

それぞれの条件のときにわざわざselect文で完結してしまっているからですね。
条件を配列で持っておき、andでつなげてSELECTとすることで、複数条件で検索可能となります。

※とりあえず現状のソースを活かすので冒頭に挙げたエスケープは入れてません。

    $where = [];
    if (isset($_POST['sex']) && $_POST['sex'] != "") {
        $where[] = " ( sex = '".$_POST['sex']."' ) ";
    }
    if (isset($_POST['syozoku']) && $_POST['syozoku'] != "") {
        $where[] = " ( syozoku like '%".$_POST['sex']."%' ) ";
    }

    $sql = 'SELECT * FROM student';

    if(count($where) > 0){
      $sql .= " where ".implode(" and ",$where);
    }

質問2

全て「イコール」で検索しているからです。
現状のデータ構造を変えられないのであれば、とりあえず質問1の回答のソースのようにlikeの部分一致で検索すれば良いはず。

余談:
所属名称や性別などはコードで持っておき、別のテーブルにした方が良いです。
今回の所属名や性別などは名称があまり変わらないかもしれませんが、
日本語や名称を持っておくと万が一名称が変わったときに管理しきれなくなります。
所属も複数登録する可能性があるのであれば、同じテーブル内で規則性ないセパレータで持つよりも、
「生徒所属管理テーブル」のようなものを作って、「生徒コード」「所属コード」で1対多の関係で持っておき、
生徒テーブルから随時参照するような形でしておく方が、管理はしやすくなります。それぞれの役割がはっきりします。
1つのテーブルに全て詰め込むのは後々のメンテナンス性まで考えた場合に賢いやり方ではありません。

 後学のためにテーブル設計参考例

何かしらの課題っぽいので変えられない部分もあるかと思いますが、テーブル設計の例を挙げておきます。

学生テーブル(PK:学籍番号)

学籍番号 氏名 メールアドレス 性別
001 山田太郎 tarou@hogehoge.com 0
002 山田花子 hanako@hogehoge.com 1

所属テーブル(PK:所属コード)

所属コード 所属名称
001 運動部
002 生徒会
003 文化部

学生所属管理テーブル(PK:学籍番号、所属コード)

学籍番号 所属コード
001 001
002 002
002 003

取得の仕方としては、
学生テーブルから取得するときに
学籍番号で学生所属管理テーブルを参照し、
所属名称は学生所属管理テーブルの所属コードから
所属テーブルを参照するようにします。


SQL一発でjoinでつなげても良いですし、学生テーブルのみ取得してあとは個別にSQL発行しても構いません。
男女は0なら男、1なら女と直接出力時にphpに書いても良いと思います。それか設定ファイルに持つとか。
やり方は1つではないので色々と考えて、やってみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/22 17:11

    回答ありがとうございます。
    おっしゃる通り課題です。
    プログラム、データベース、構成は自由なのでいろいろ試してみます。

    キャンセル

+2

回答1

MySQLに渡すクエリで検索条件をANDで2つ指定すれば全てを満たした行のみ返ってきます。

具体的には

SELECT * FROM students WHERE sex = '女' AND syosoku LIKE '%文化部%';

で表示されます。

しかし、 LIKE句で中間一致検索をしているため、syozokuカラムに索引を作成しても
使われないため、レコード件数が多い(数万とか)と性能問題を引き起こします。

回答2

これも

SELECT * FROM students WHERE syosoku LIKE '%運動部%';

というように中間一致検索で解決できます。

参考

本来はテーブルを正規化すべきかと思います。
http://tech.nikkeibp.co.jp/it/article/COLUMN/20130416/471174/

中間一致検索について
https://so-kai-app.sakura.ne.jp/blog/1527/2016/12/14/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • PHP

    24001questions

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

  • MySQL

    6989questions

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