鈴木商店の嶋崎です。こんにちは。
今回は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)で検証していますが、どのデータベースでも使えると思います。
以上です。