- m_s_modified
- 1382
- 0
- 0
- 0
LEFT JOINの間違った例 http://codepad.org/qk8OvmOh 正しくはこちら http://codepad.org/aYJimXh4 商品マスタをLEFT JOINする必要はないはずですが、LEFT JOINにするところが多いですね。
2010-03-18 19:32:19例では商品マスタをLEFT JOINでつないでいますが、つまりは、商品CDがNULL、または、商品マスタに存在しない商品CDが売上明細に入るということを意味します。それが本当なら、かなりばっちいテーブル設計と呼んでいいでしょう。
2010-03-18 19:38:10「無条件でLEFT JOINにする」その感覚が考えない結合を助長させバグを生みます。つまり先ほどのサンプルが間違いと思わなかった人は、本当にLEFT JOINが必要なときに簡単にバグを作ってしまいます。(今回もばっちい構造だったときはバグです)
2010-03-18 19:45:12副走査テーブルになるというのは、主走査テーブル以外のSELECT句で必要なカラム例えば、商品マスタにある、商品名と定価が欲しいときは商品マスタをつなぎます。売上金額を見たいだけなら不要ですね。ER図から直接つながらない中間テーブル持つなぎましょう。
2010-03-18 19:50:49副走査テーブルをつなぐとき、参照整合性が設定され、対象のカラムにNOT NULL制約が指定されているときは INNER JOIN でつなぎます。それ以外はLEFT JOINでつなぎます。
2010-03-18 19:55:55主走査テーブル、INNER JOIN でつながっている副走査テーブルにあるカラムはWHERE句に入れることができます。それ以外はWHERE句に入れてはいけません。
2010-03-18 19:58:46空なら良いのですけれど、雑品は「雑品」というレコードを作っておくか、商品名を入れられたときに自動登録。これはサロゲートキーを使うかどうかという話なるでしょうが。QT @asuki_syobon:@Sikushima コードがないこと自体は割りとある話だと思います。
2010-03-18 20:04:38WHERE条件で副走査テーブルのカラムを指定したいとき、抽出条件か結合条件なのか十分に考慮する必要があります。「LEFT JOINなら結合条件」と決めても良いのですが、くどいけれど無条件にLEFT JOINにしていたら、どちらか分からないのです。
2010-03-18 20:05:53サンプルコードのように、LEFT JOIN なら、結合条件に書く必要がある。「抽出したあと結合」「結合したあと抽出」の違いです。結合した後、抽出ならWHERE句でかまいません。
2010-03-18 20:08:34意識しないでLEFT JOIN を書いていると、プロジェクトの後半で「xxxが入力されてないとき出力されないデータがある」というバグが頻出します。LEFT JOINの部分をサブクエリーにしたりする人もいますが、それは猛烈にパフォーマンスが悪くなるのでやめましょう。
2010-03-18 20:10:40副走査テーブルにもないテーブルのカラムが抽出条件に必要になったとき、WHERE句(またはHAVING句)でサブクエリーになります。抽出のためにINNER JOINを使うのは意味が分かりにくくなるので避けるべきです。
2010-03-18 20:13:25それはね。昔、コーディング規約に基本LEFT JOINにしなさい。とか、必ずLEFT JOINとか、あったのよ。 QT @futabachannel:@Sikushima 内部結合すれば結局一番楽になるのに何で考えなしにほいほいleft outer joinする人がいるんだろ…
2010-03-18 20:14:54書き方としては、まず、主走査テーブルを書き、JOINの形が分かるように主走査テーブルと同じインデントにJOIN と繋げるテーブルを書きます。結合条件はもう一つインデントして書いていきます。
2010-03-18 20:16:58http://codepad.org/aYJimXh4 プログラム的な意味では、売上明細が主走査テーブルにした方がきれいですが、業務的な意味でヘッダからつないでいます。この部分は、おそらく業務的な意味を優先する方が多いと思います。
2010-03-18 20:19:57インデントはプロジェクト毎にイロイロと決まりがあると思いますが、JOINの型は非常に重要なので、後から見て分かり易いように書きましょう。特にテーブルが1行に複数あると、後から読むのは大変ですよ。(1個目と2個目だけですから、大して被害はないけれど)
2010-03-18 20:26:43主走査テーブルとそれにつながるJOINの形がはっきりすればSQLは読めます。主走査以外は、FROM、WHERE句のロジックには関係しないということですから、最終的に20、30個テーブルがつながっても大して難しくはない。名称をとるだけのテーブルなど無視して読めばよい話です。
2010-03-18 20:29:17EXISTS ですけれど、たくさん使いますよ。慣れないうちは難しいけれど、慣れれば簡単です。QT @TreeBoa:@Sikushima EXISTとか実践でつかったりするの? DBの問題にでてたけど???
2010-03-18 20:30:40人のソースを読むときはインデントをやり直さないと読めないことが多く、インデントをやり直しても主走査を何にしたかったのか分からないときもある。つまり、意味を分からず書いているから、SQL文が意味を成していない。GUIで書いたのをコピペしてあるのも解析にメチャクチャ時間が掛かる。
2010-03-18 20:35:17とにかく、まず、FROM WHERE句を徹底的にきれいに書けるようにすること。FROM、WHERE句が完璧に書けたら、それをクエリービルダーに貼り付けてSELECT句などを書くとよい。カラムの羅列のためにツールを使って時間短縮するのは良い方法です。
2010-03-18 20:36:23要望を聞いた瞬間に、主走査テーブルとWHERE句まで作る。ロジックに関連する副走査テーブルを合わせて要望を検討する。こうすればSQLは会話のペースでできるのです。
2010-03-18 20:37:38パフォーマンスは、主走査テーブルとWHERE句(& ORDER BY)で基本的には決まる。20、30個つないだモノと、SELECT * で主走査テーブルとWHERE句(& ORDER BY)に省略したモノを作ってパフォーマンスを比べてみれば分かる。
2010-03-18 20:39:42基本、ストアドプロシージャなら気にする必要はないです。ループの中で実行されるからSQLの再利用を考慮しなければならないわけで、1回で処理するようなやり方なら気にする必要はないです。速くなって数ミリ秒ですよ。 QT @Nakunaru:@Sikushima SQLのインデントは
2010-03-18 20:45:01もちろん、テーブルの構造が悪く、サブクエリーが入ると、その部分のパフォーマンスを考慮する必要があるけれど、サブクエリーも単体で流したときのパフォーマンスを追加し、結果がインデックスなしで結合されることを意識すれば予測はつく。インデックスを外してなかったら3倍でのパフォーマンス。
2010-03-18 20:45:51FROM句のLEFT JOINは http://codepad.org/3Tubw9P4 のようなパターンのときに非常に間違いが多くなる。この手のテーブル構造にはサロゲートキーを採用すべきなのですが。というかサロゲートキーをデフォルトで採用してもよい。
2010-03-18 20:47:22検索エンジンの様な特殊な場合は、できる限りインデックスのメモリー使用量を減らしたいのでサロゲートキーすら避けますが。
2010-03-18 20:48:21