生島 勘富SQL講座
@naka_aki_spl O/Rマッパはミスマッチを超えるためにあるので、どこまで行ってもRDBの構造を引きずってしまいますから、オブジェクト指向と呼ぶならテーブルと一対一のパターンだけじゃないかと思ったり。
2010-06-02 16:23:27SQLが書けないというのは、FROM句、WHERE句が分かってないということ一番の理由。FROM句、WHERE句が書けるようになれば、後は枝葉末節です。
2010-06-02 19:48:57サンプルは売上ヘッダ・売上明細・得意先マスタ・商品マスタがあるとします。商品には「雑品」としてコードが与えられてないモノがあるとします。
2010-06-02 19:50:39基本的には LEFT JOINの間違った例 http://codepad.org/qk8OvmOh 正しい例 http://codepad.org/aYJimXh4 についての説明です。
2010-06-02 19:52:18余談ですが、顧客が「『雑品』としてコードがないモノがある」といっても、それを真に受けて設計するのは良くない。顧客は裏で自動登録されているかどうかは知ったことではない。「これを顧客の要望です!」ってやるから、テーブル構造が汚くなる。
2010-06-02 19:53:50自動登録してもインデックスが当たる形になっていたら、その方がパフォーマンスが良くなる。最悪、ID:999999 雑品 としてマスタ登録する方がよい。RDBはリレーションしないデータがあると、あちこちで不都合が起きる。
2010-06-02 19:55:58それはともかく、JOINの特徴。つなぐ相手がユニークでなければ返されるレコードが増えます。ですから、同じレコードが出力されるときは、ほぼ、FROM句(JOIN)にバグがあります。DISTINCTで逃げないようにね(苦笑)
2010-06-02 19:57:37まず最初に、ループの基礎になるテーブルを考えます。手続き型の言語では対象レコードが多い(つまりトランザクション)をメインループに選ぶことが多いでしょう。SQLは似ていますが、最終的に欲しい件数が入っているテーブルと考えてください。
2010-06-02 19:59:37今回は売上ヘッダ・売上明細をメインループに選びます。私は無意識にやっていたけれど、主キーどうして繋がる所まで(サロゲートキーを使わず、複合キーの場合)はメインループと考えてください。
2010-06-02 20:01:43売上ヘッダ.伝票番号(主キー)= 売上明細.伝票番号(主キーの一部)となるところまでがメインループで基本的にINNER JOINでつなぐ。ここで外部結合を使う必要があるとしたらテーブル設計を見直そう。どっかおかしい。
2010-06-02 20:03:19次に、参照整合性がついている、NOT NULL制約があるカラムとマスタに対しては、INNER JOINでつなぎます。
2010-06-02 20:05:38その後、NULLが入ったりするカラムと結合します。そのNULLのレコードを抽出したいとき、LEFT (OUTER) JOIN で結合します。
2010-06-02 20:08:33LEFT (OUTER) JOIN はベン図の左側の円がまん丸で、右側が欠ける結合。RIGHT (OUTER) JOIN はその逆。SQLは一行で書けるので、左側のテーブルが円がまん丸。のイメージを持ち続けること。
2010-06-02 20:10:44「無条件でLEFT JOINにする」「LEFT JOINにしないとデータが出ないときがある」とかいう人もあるけれど、本来は闇雲に使うべきではありません。
2010-06-02 20:13:02LEFT JOINの間違った例 http://codepad.org/qk8OvmOh 正しくはこちら http://codepad.org/aYJimXh4 商品マスタをLEFT JOINする必要はないはずですが、LEFT JOINにするところが多いですね。
2010-06-02 20:17:24なぜ間違いかというと、LEFT JOINを選択しているということは、「商品マスタにない売上明細も出力したい」という意思表示です。
2010-06-02 20:19:39ところが、「商品マスタにない売上明細」に紐付くカラムはすべてNULLになっています。つまり、WHERE句の「s.商品種別 = 'Z'」は「NULL = 'Z'」つまり FALSE になりますので出力されません。
2010-06-02 20:21:51ベン図の欠けた方に抽出条件を書くと出力されなくなって、INNER JOINと同じ結果になると覚えても良いでしょう。
2010-06-02 20:24:03LEFT JOINの間違った例 http://codepad.org/qk8OvmOh を見て直感的に気持ち悪い。と思わないと潜在バグを量産しているかも知れません。
2010-06-02 20:25:24冗談抜きで、数億規模の案件で 例 http://codepad.org/qk8OvmOh のようになっているものが、数千ってこともあった。そのうち数10%がバグで、他はINNER JOINでも良かったもの。
2010-06-02 20:28:56間違えないためには、抽出条件なのか、結合条件なのか考えれば良いのですが、ベン図で考えてもいいですし、LEFT JOINでつないだテーブルのカラムはWHERE句に入れてはいけないと覚えても良い。
2010-06-02 20:32:59ちなみに、商品マスタがメインループになる場合はどんな場合でしょう。それは、また明日 ノシ~
2010-06-02 20:33:43昨日は、LEFT JOINの間違った例 http://codepad.org/qk8OvmOh 正しい例 http://codepad.org/aYJimXh4 についてつぶやきました。
2010-06-03 19:00:01