しばらくの間、 SQL で書かれた、様々な集計クエリを読んでいたのですが。どうも、クエリが読みにくくていけない、と思いまして、いまさらながらですが、 SQL クエリの書き方について考えました。
SQL クエリの読みにくさの原因というのは、いくつかあるのですが、一番大きいのは、 FROM 句と、 WHERE 句が離れてしまうことにあると思います。クエリを作るときには、テーブル/リレーションごとに条件を考えて、クエリを組み立てていくと思います。これを、 昔ながらのスタイルで SQL に書くと、 FROM 句にリレーションが並び、 WHERE 句にリレーションの条件が並ぶ、という、リレーションと条件とが分離した形になります。
クエリの読み手がクエリを読む際には、 クエリを作るときの手順を逆に行なうことになります。 WHERE 句に並んでいる条件が、 FROM 句のどのリレーションにかかっているのか、 FROM 句のリレーションごとに、 WHERE 句の条件を並べなおして、クエリからどのような結果が出力されるかを読み取ろうとするわけです。
このようなクエリは、例えば、以下のようなものになります 。
select
a.A_ID,
trim(a.A_LNAME) || ',' ||
trim(a.A_MNAME) || ',' ||
trim(a.A_FNAME) as a_name,
ol.OL_QTY
from
CUSTOMER c,
ADDRESS ad,
COUNTRY co,
ORDERS o,
ORDER_LINE ol,
ITEM i,
AUTHOR a
where
ad.ADDR_ID = c.C_ADDR_ID and
co.CO_ID = ad.ADDR_CO_ID and
co.CO_NAME = 'Japan' and
o.O_C_ID = c.C_ID and
o.O_STATUS = 'SHIPPED' and
ol.OL_O_ID = o.O_ID and
i.I_ID = ol.OL_I_ID and
i.I_PUB_DATE >= date '2007-08-01' and
i.I_PUB_DATE < date '2009-09-01' and
a.A_ID = i.I_A_ID and
c.C_DISCOUNT >= 0.1
order by A_ID
このように、いちいち、 WHERE 句と、 FROM 句を頭の中で照合するのは、リレーションの数、条件の数が増えてきますと、やっておれなくなってきます。このため、別途、メモを作成して、リレーションごとに条件をまとめてみたりするわけですが、 無用な手間、という感じなんですよね。
そこで、私がこうしたクエリを書くときにやるのが、 WHERE 句にある条件を、すべて JOIN 句に書く、というやり方です。 さらに、 FROM 句の一番目のテーブルの条件だけは、 WHERE 句に残ってしまうため、あえて、サブクエリにします。
こうしますと、条件がリレーションごとにまとまりますので、かなり読みやすくなるのではないかと思います。
select
a.A_ID,
trim(a.A_LNAME) || ',' ||
trim(a.A_MNAME) || ',' ||
trim(a.A_FNAME) as a_name,
ol.OL_QTY
from (
select C_ID, C_ADDR_ID
from CUSTOMER
where C_DISCOUNT >= 0.1) c
inner join ADDRESS ad on
ad.ADDR_ID = c.C_ADDR_ID
inner join COUNTRY co on
co.CO_ID = ad.ADDR_CO_ID and
co.CO_NAME = 'Japan'
inner join ORDERS o on
o.O_C_ID = c.C_ID and
o.O_STATUS = 'SHIPPED'
inner join ORDER_LINE ol on
ol.OL_O_ID = o.O_ID
inner join ITEM i on
i.I_ID = ol.OL_I_ID and
i.I_PUB_DATE >= date '2007-08-01' and
i.I_PUB_DATE < date '2009-09-01'
inner join AUTHOR a on
a.A_ID = i.I_A_ID
order by A_ID
というわけで、 私は、 WHERE 句ではなく、 JOIN 句に条件を書く、というスタイルを推奨してみたいわけです。
最近のコメント