質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

2回答

7135閲覧

MySQLのLEFT JOINとNOT EXISTSの違い

msx2

総合スコア174

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

0クリップ

投稿2017/04/08 01:29

編集2017/04/08 02:43

データの検証をするためにSQLを書きましたが思った結果になりません。

table_aとtable_bを比較して、table_aだけに存在するデータを得るのが目的です。

■table_a

item_codecolor_codesize_code
AAABK10
AAABK20
BBB00
CCC0S
CCC0M

■table_b

iditem_idcolor_idsize_id
110121
210131
310211
410312
510313

■item

iditem_code
101AAA
102BBB
103CCC

■color

idcolor_code
10
2BK1
3BK2

■size

idsize_code
10
2S
3M

SQL

1select 2 a.item_code, 3 a.color, 4 a.size, 5 b2.id 6from table_a as a 7left join ( 8 select 9 b.id 10 i.item_code, 11 c.color_code, 12 s.size_code 13 from table_b as b 14 join item as i on b.item_id = i.id 15 join color as c on b.color_id = c.id 16 join size as s on b.size_id = s.id 17 ) as b2 18on (a.item_code = b2.item_code 19and a.color = b2.color_code 20and a.size = b2.size_code)

table_aの全レコードとtable_bに存在しないデータはb2.idにNULLが入る結果になると思っているのですが、本番データで実行してみると半分くらいb2.idにNULLが入ります。
実際にはほとんどのレコードが一致しているのでこれは期待した結果ではありません。

ちなみにleft joinではなくjoinとすると期待した通りに結合します。

また、やり方を変えて上記のサブクエリとnot existsでセレクトするとtable_aだけに存在するレコードが得られます。

一応目的は果たせているので仕事は進められているのですが、どうしてleft joinだとうまくいかないのかわかりません。

私のleft joinの理解が間違っているのだと思いますが、この結果になる理由を教えていただけないでしょうか。

よろしくお願いします。


not exists句を使ったSQLです、これはうまくいきました

SQL

1select 2 a.item_code, 3 a.color, 4 a.size 5from table_a as a 6where not exists ( select * from 7 (select 8 b.id 9 i.item_code, 10 c.color_code, 11 s.size_code 12 from table_b as b 13 join item as i on b.item_id = i.id 14 join color as c on b.color_id = c.id 15 join size as s on b.size_id = s.id 16 ) as b2 17where a.item_code = b2.item_code 18and a.color = b2.color_code 19and a.size = b2.size_code 20)

追記

table_aの件数は800件、table_bは810件
table_aとtable_bが一致している数790件
1つ目のSQLの実行結果は800件でNULLが入る件数が400件
1つ目のSQLのleft joinをjoinに変更すると790件になります
2つ目のSQLを実行すると10件になります。

left joinの結果だけがおかしいみたいです。
謎です。。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

left joinについて
table_aの全レコードとtable_bに存在しないデータはb2.idにNULLが入る結果になる
という認識は誤っていないと思います。
上記のSQLではカンマがなかったり、カラム名が間違っていたりでうまく動きませんでしたが、きちんと試されましたか?

私の環境で実行すると、上記のデータとSQLの結果は下記の通りです。
イメージ説明

ちなみに、table_bのid5を削除すると下記の様になります。(id5だけがnullになってます)
イメージ説明

再度、ご自身の書いたSQLを見直してみると良いかもしれません。

投稿2017/04/08 02:04

motuo

総合スコア3027

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

msx2

2017/04/08 02:31

ご回答および検証いただきましてありがとうございます。 質問に記載したSQLは実際のSQLを見ながら簡略化して書いたもので間違いがあったとのことで失礼しました。 確かに件数が少ないと期待した動きになるみたいです。 実データも800件程度とたいした件数ではありませんが、上記一つ目のSQLを実行すると400件くらいNULLが入ります。 不思議なのはleft joinをjoinに変更するとleft joinでNULLの入っていないレコードだけが取得できるはずですが、joinだけの方は800件ほど出てきます。 left joinの認識が間違いでなければこの結果はMySQLのバグかも知れませんね。
motuo

2017/04/08 02:56

正直、このレベルの構文と件数でMySQLにバグが出るとは、中々考えずらいのですが… やはりSQLもしくはデータに何らかの誤りがある、という観点で精査してみると良いと思います。
guest

0

自己解決

別の環境(レンタルサーバー)のMySQLに同じデータをインポートして同じSQLを実行したところ期待した結果になりました。

■MySQLのバージョン
開発環境:5.6.20
レンタルサーバー:5.5.45

こういうこともあるんですね、いい経験になりました。
開発環境のMySQLをアップデートしようと思います。

投稿2017/04/08 10:17

msx2

総合スコア174

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問