ラベル sql の投稿を表示しています。 すべての投稿を表示
ラベル sql の投稿を表示しています。 すべての投稿を表示

2012年9月30日日曜日

(初心者向け)SELECT文を考える時には最終アウトプットを強く意識する。


SELECT文を考える時、何となくjoinやgroup byとか使ってませんか?もしくはメインとなるテーブルを意識していますか?

SELECT文は非常に便利なので気づかないのですが裏で実行されている事は(非常に簡単に言うと)

 ・縦*横の二次元の表を付きあわせ、新たな縦*横の二次元の表を作成

しているだけなのです。


その際に、一行の粒度が変わる事に注意が必要です。多重度が大きい側にjoinすると、自ずと一行の粒度が変わってしまう(行が増えてしまう)為、初心者のうちは自分が何をしているのか分からなくなります。

例えば次のER図があり、


最終的に次のような表が欲しい場合、どういうSQLを書きますか?


私は概ね次のステップでSELECT文を考えます。

・最終アウトプットの一行の粒度を確認する。
  この場合注文明細の行数が最終アウトプットの行数と同じ

・その粒度にあったテーブルをメインの表にする。
  from 注文明細を起点に考える

・そこに枝葉のテーブルを加える。その時に行の粒度を変えない(膨らまさない)。
  from 注文明細
    inner join 注文 on 注文.注文番号 = 注文明細.注文番号
    inner join 顧客 on 顧客.顧客NO = 注文.顧客NO
    inner join 商品 on 商品.商品NO = 注文明細.商品NO

from 注文からはじめる人も多いと思いますが、注文明細をjoinした時に行が膨れるため、考えを単純化する目的で、こんな簡単な場合でも徹底して明細側をメインテーブルにします。

あまりにも意図せず膨らましてしまい、group by/distinctでお茶を濁そうとする人が多そうなので記事にしてみました。もちろん集計が入ってくるとこの限りでは無いのですが、「最終アウトプットの一行の粒度」を意識する事は非常に重要です。


2010年12月29日水曜日

distinctってそんなに使うのか?

SQLのdistinctは使い所によっては、必要なキーワードだが、訳も分からず使われている事も多い。「膨らんだから書いとけ!」見たいな感じで。

若者のSQLを見ていると、同じ使い方が多いことに気づいた。例えば

foo: id, name
bar: id, foo_id, flag

というテーブル構成で、「barでflagがたっているfooの行を取得」が課題だった場合

select
  f.id, f.name
from
  foo f inner join bar b on b.foo_id = f.id
where
  b.flag = true

と書いてしまったが為に、最終的にselect句にdistinctをつけるはめに。。

これは「fooからデータを取得する際の抽出条件」と認識すれば

select
  f.id, f.name
from
  foo f
where
  exists (select 'x' from bar b where b.foo_id = f.id and b.flag = true)

と書けるはずで、distinct は不要だ。

selectは、縦*横の新しい表を取得する物で、「1行が意味する概念」は何かを、はっきり意識できていないからではと思う。