MySQLで1対多の、多の方に複数条件がある場合の書き方

2017年09月25日
投稿者:嶋崎聖
カテゴリ:DB, MySQL, PHP タグ:, , ,
logo-mysql-170x115

鈴木商店の嶋崎です。こんにちは。

今回はSQLの話です。
ひとつのテーブルに対して条件がある場合、whereで絞り込むだけで良いので簡単です。
1対1の場合もinner joinをしてon条件で絞り込めば、望む結果が得られます。
また、1対多であっても、検索条件がひとつの場合、実質1対1になるので、そう問題ではありません。

問題は1対多で、かつ条件が複数ある場合です。

例えばBlogテーブルと、Tagテーブルがあるとします。
1つのエントリに対して、複数のtagが設定できるとき、
複数のタグでOR検索(条件のどれかのtagを含んでいる)、AND検索(条件で指定した全てのtagを含んでいる)をしたいと思います。

ググると、条件個分UNIONとか、条件個分JOINと言う方法が見つかりましたが、
今回はPHP等でプログラムにしやすい形を目指しての方法になります。

まずは準備、以下のテーブルがあるとします。

blog

blog_id title body
1 こんにちは こんにちはこんにちは
2 こんばんは こんばんははこんばんは

tag

tag_id name
1 挨拶
2
3

blog_tag

blog_id tag_id
1 1
1 2
2 1
2 3

パターン1

  • OR検索の場合

  • AND検索の場合

existsです。条件のどれか一つでも当てはまればexistsはtrueなので、OR検索できます。
条件に全て当てはまった件数と条件個数が等しければtrueを返すようにすればAND検索になります。

パターン2

  • OR検索の場合

  • AND検索の場合

EXISTSをinner joinに書き換えたパターンです。
MySQLのバージョンや、データ件数等によってはこっちの方が早いと思います。

ORにしてもANDにしても多少の構造の管理は必要とは言え、基本的には条件が増減するだけなので、シンプルです。

PHPで実装する場合は、条件がない場合はexists及びjoinをしないようにします。
あとは条件のプレースホルダの増減と、AND検索の場合にhavingのところにも条件数のプレースホルダを与えるだけです。

CakePHPであればconditionsに配列そのまま渡すだけですね。

Aurora(MySQL5.6)で検証していますが、どのデータベースでも使えると思います。

以上です。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です