この投稿の主旨
自分が作成したクエリーとそれを手直ししてもらったクエリーを比較したとき、自分のクエリーがとても冗長だったもので、その戒めのためにもこの投稿をしましたorz..
問題となったのは、親子関係のあるデータ構成があり、1回のクエリーで親と子の両方を取得したい場合がありました。プログラム上では親のデータは1回しか参照しないにも関わらず、親と子の両方を取得するクエリーで子のレコードに必ず親のデータもくっついてきて、データ量が肥大化してました。
実際のデータ構成と近い形で以下に記載します。
テーブル構成
- 以下のテーブル構成で親子関係を表す
humansテーブル |
---|
id |
name |
human_relationsテーブル |
---|
parent_id |
child_id |
humans 1 - n human_relations
例)パパと子ども3人の場合
humans
id | name |
---|---|
1 | パパ |
2 | 子ども1 |
3 | 子ども2 |
4 | 子ども3 |
human_relations
parent_id | child_id |
---|---|
1 | 2 |
1 | 3 |
1 | 4 |
冗長なクエリーはこちら
// これだと子どものレコードに必ず親の情報がくっついてきて無駄になる
SELECT
parent.id as parent_id, parent.name as parent_name, child.id as child_id, child.name as child_name
FROM humans parent
LEFT JOIN human_relations hr ON parent.id = hr.parent_id
LEFT JOIN humans child ON hr.child_id = child.id
WHERE parent.id = :id
結果
parent_id | parent_name | child_id | child_name |
---|---|---|---|
1 | パパ | 1 | 子ども1 |
1 | パパ | 2 | 子ども2 |
1 | パパ | 3 | 子ども3 |
スマートなクエリーはこちら
// これだと親と子どもが分離されて余計なデータがなく取得できる
SELECT humans.id, humans.name
FROM humans LEFT JOIN human_relations hr ON humans.id = hr.child_template_id
WHERE (hr.parent_id = :id OR humans.id = :id)
AND humans.deleted IS NULL
結果
humans.id | humans.name |
---|---|
1 | パパ |
2 | 子ども2 |
3 | 子ども3 |
4 | 子ども4 |