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

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

ただいまの
回答率

87.94%

MySQLの複数条件検索

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 6,064

score 15

WordpressにてMySQLのデータベースからデータを検索して
取り出す仕組みを作成しています。

二つのカラムに対してそれぞれ検索条件に一致する物を取り出し、
条件指定が無い場合は全て読み出すようにしたいと考えています。
この場合、どのように条件をプレースホルダへ渡せば良いでしょうか。

具体例は次の通りです。

テーブルには三種類のカラムがあります。
1.車名
2.メーカ 
3.タイプ

検索条件(変数)は$makerと$typeの二種類で、
値はセレクトフォームからPOSTで取得する形です。

$maker="トヨタ", $type="セダン"の場合は問題なく該当車名が取り出せます。
$maker="トヨタ"でタイプを問わずに検索する、
$type="セダン"でメーカを問わずに検索する、
またはどちらも問わずに検索する場合の方法についてご教示いただけないでしょうか。

検索部分のコードは次の通りです。

$maker = $_POST['maker']; 
$type = $_POST['type'];

$sth = $wpdb->prepare("SELECT name FROM $wpdb->data WHERE maker = '%s' AND type = '%s'", $maker, $type);
$rows = $wpdb->get_results($sth);
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+3

プレースホルダーに値を送るんじゃなくて、emptyだったらWHEREを変えればいいんじゃないでしょうか?
単純なif文のような気がしますが。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/06/05 11:42

    ご回答いただきありがとうございます。
    自分が知らない方法があるかなと複雑なことばかり考えていましたが、
    確かにif文でSELECT文自体を場合分けしてしまえばシンプルに実現できますね。

    キャンセル

+2

1.POSTされた$makerと$typeが両方とも空かどうか判定する

if(isset($maker) && isset($type)){
    $sth = $wpdb->prepare("SELECT name FROM $wpdb->data ");
}

あと、データベースには三種類のカラムがあります。 というのは、おそらく
テーブルには三種類のカラムがあります。が正解かと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/06/06 10:38

    ご回答いただきありがとうございます。
    If文での分岐を使う場合は紹介いただいた方法で
    判定し、SELECT文を変えるのが良さそうですね。

    データベースと書いた点は、ご指摘の通りテーブルが正しい表現ですね。
    質問文を修正しました。
    ありがとうございました

    キャンセル

checkベストアンサー

0

こんな感じじゃないですか?

<form method="post">
maker:<input type="text" name="maker" value="トヨタ"><br>
type:<input type="text" name="type" value="セダン"><br>
<input type="submit" value="search"><br>
</form>
<?PHP
$maker = filter_input(INPUT_POST,'maker'); 
$type =  filter_input(INPUT_POST,'type'); 
$sql="SELECT name FROM tbl WHERE 1 ";
$params=[];
if(!is_null($maker) and $maker!==""){
  $sql.="AND maker=%s ";
  array_push($params,$maker);
}
if(!is_null($type) and $type!==""){
  $sql.="AND type=%s ";
  array_push($params,$type);
}
array_unshift($params,$sql);

print_r($params);
//$sth =call_user_func_array(($wpdb,'prepare'),$params);
?>

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/06/05 11:37

    コードまで合わせてご回答いただきありがとうございます。

    $sth =call_user_func_array(($wpdb,'prepare'),$params);
    この部分で$paramsの引数を$wpdb->prepareに投げて実行しているのかと思いますが、HTTP ERROR500が出てしまいます。

    原因が分かりそうでしたら教えていただけませんでしょうか。
    (分からないなりにいじってみましたが、エラーは出ずとも検索結果も出ず...。)

    キャンセル

  • 2017/06/05 11:43

    失礼しました
    $sth =call_user_func_array(($wpdb,'prepare'),$params);
    ↓↓↓
    $sth =call_user_func_array([$wpdb,'prepare'],$params);
    でどうでしょうか?

    キャンセル

  • 2017/06/06 10:40

    ありがとうございます。
    無事、動作いたしました。

    皆様からPHPでif文分岐、@パラメータへALLを渡すなど、
    複数案をいただけましたので、
    実環境でそれぞれ試してみて、合っているものを実装したいと思います。
    皆様ありがとうございました。

    キャンセル

0

PHP は分からないので PHP で使える MySQL のプロバイダで可能かどうかわかりませんが・・・

クエリの WHERE 句を工夫して、例えば以下のようにし(プロバイダに Connector/NET を使った場合の例です)、条件指定がない場合はパラメータ @maker, @type に 'ALL' を渡す、指定がある場合は指定された値を渡すというのはいかがですか?

WHERE (@maker='ALL' OR maker=@maker) 
  AND (@type='ALL' OR type=@type)

----- 2017/6/6 12:11 追記 -----

2017/06/06 11:53 の私のコメントで「詳しくは回答欄に書いておきます」と書きましたが、それを以下に書いておきます。

まず基本的な話として、パラメータ化クエリというのをご存知でしょうか? 

以下の記事によると PHP + MySQL でも使えるはずですので、SQL インジェクション防止とパフォーマンス向上のため必ず使うようにしてください。

パラメータ化クエリ
http://use-the-index-luke.com/ja/sql/where-clause/bind-parameters

質問者さんが最初の質問に書かれたコードを見ると、POST  されてきたユーザー入力で SELECT クエリの文字列を組み立てているように見えますが、もしそうだとすると、それは SQL インジェクションしてくださいと言っているようなものです。なので、まずパラメータ化クエリを使うようにしてください。

パラメータ化クエリに関する知識が十分でないと話が通じにくいのですが、とりあえず @ のことについて書いておきます。

コメントにも書きましたが、パラメータ化の際のプレースホルダの命名規則には DB やプロバイダによっていろいろ違いがあり、頭に @ を付けるのは MySQL + Connector/NET を使った場合の規則です。

上に紹介した記事によると、PHP + MySQL では命名規則が異なるようで、疑問符 (?) で指定される位置パラメータマーカーが使用されるそうです。

なので、WHERE 句は、上に書いた @maker や @type のような名前付きパラメータではなくて、位置パラメータマーカー (?) を使って、

WHERE (?='ALL' OR maker=?) 
  AND (?='ALL' OR type=?)

のようになると思います。

注:PHP の開発環境を持っていないので未検証・未確認です。もしハズレだったらすみません。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/06/06 10:39

    ご回答いただきありがとうございます。

    簡単に試してみましたが、うまく検索ができませんでした。
    ただ、@を使った検索について私自身の不理解が大いにあると思うので
    勉強してから再度試してみます。

    キャンセル

  • 2017/06/06 11:53

    > @を使った検索について私自身の不理解が大いにあると思うので

    「検索」ではないです。パラメータ化の際のプレースホルダの命名規則には DB やプロバイダによっていろいろ違いがあり、頭に @ を付けるのは MySQL + Connector/NET を使った場合の規則です。PHP では命名規則が異なると思います。

    詳しくは回答欄に書いておきます。

    キャンセル

  • 2017/06/08 16:02

    詳細説明ありがとうございます。
    プレースホルダの命名規則の事だったのですね。
    勘違いしておりました。

    Wordpressの場合、ご紹介いただいたウェブサイトで、PHPでのバインドパラメータの使い方にある、パラメータのバインドとエスケープ処理を$wpdb->prepare関数がやってくれるとの理解です...
    が、不安なのでもう少し調べて検証してみます。

    キャンセル

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

  • ただいまの回答率 87.94%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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