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

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

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

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Q&A

解決済

5回答

26345閲覧

【PostgreSQL】結合テーブルにデータがない場合、レコードが抜け落ちる

dsk

総合スコア44

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

1グッド

3クリップ

投稿2015/06/23 00:44

編集2015/06/23 02:19

PostgreSQLを利用しています。

やりたいこと

2つのテーブルを結合して、下記のようなデータを取りたいです。

name | total_sales | productcreated |
product1 | xxx | YYYY.MM.DD |
product2 | xxx | YYYY.MM.DD |
product3 | xxx | YYYY.MM.DD |
product4 | xxx | YYYY.MM.DD |
product5 | xxx | YYYY.MM.DD |

name,productcreatedはtbl1に、
total_salesはtbl2に格納されています。

やったこと

こちらのSQLを実行しました。

lang

1select 2 product_name, 3 tbl2.total_sales, 4 to_char(tbl1.created, 'YYYY.MM.DD') as productcreated 5 6from tbl1 7inner join tbl2 on tbl1.id = tbl2.product_id 8 9where product_name in ('aaaaa','bbbbbb','ccccccc','ddddd','eeeee','fffff','gggggg') 10 11order by productcreated desc 12

わからないこと

下記のようにいくつかのデータが抜けてしまいます。
※Tbl2に条件の合うデータがない場合、抜けてしまします。

name | total_sales | productcreated |
product1 | xxx | YYYY.MM.DD |
product3 | xxx | YYYY.MM.DD |
product4 | xxx | YYYY.MM.DD |

tbl2に該当のproduct_idのレコードがなくともNULLなどが入るようにし、where句で指定した全件分のデータを取得するには、どのようにsqlを記述しなおせばよろしいでしょうか。

よろしくお願いいたします。

追記

外部結合をする必要があるという回答を頂き、以下のように書き換えてみたのですが、まだ思うような結果がえられていません。(left join と right join の両方を試してみました。)
結果としては、inner join で結合をしていた時と同じになってしまっています。

lang

1select 2 product_name, 3 tbl2.total_sales, 4 to_char(tbl1.created, 'YYYY.MM.DD') as productcreated 5 6from tbl1 7right join tbl2 on tbl1.id = tbl2.product_id 8 9where product_name in ('aaaaa','bbbbbb','ccccccc','ddddd','eeeee','fffff','gggggg') 10 11order by productcreated desc 12

追記2

シンプルにしようと、関係がないと思っていた情報を省いていたのですが、実は重要な情報ではないかと思い直しましたので、追記させていただきます。
weher句のところに、別の条件を2つ書いていました。
こちらが原因でしょうか。

lang

1select 2 product_name, 3 tbl2.total_sales, 4 to_char(tbl1.created, 'YYYY.MM.DD') as productcreated 5 6from tbl1 7left join tbl2 on tbl1.id = tbl2.product_id 8 9where product_name in ('aaaaa','bbbbbb','ccccccc','ddddd','eeeee','fffff','gggggg') 10-- ★追記したもの★ 11and tbl2.xxx = X 12and tbl2.yyy = Y 13-- ★追記したもの★ 14 15order by productcreated desc
hirai0110👍を押しています

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

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

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

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

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

guest

回答5

0

ベストアンサー

left join で外部結合した場合
結合できないデータはすべてNULLになります

なので
and tbl2.xxx = X
and tbl2.yyy = Y
は条件に合致しないためWHERE句でデータをはじいています

単純にNULLの場合も取得するなら
and (tbl2.xxx = X or tbl2.xxx is null)
and (tbl2.yyy = Y or tbl2.yyy is null)
結合できないデータの場合のみNULLを許容するなら
and (tbl2.xxx = X or tbl2.product_id is null and tbl2.xxx is null)
and (tbl2.yyy = Y or tbl2.product_id is null and tbl2.yyy is null)
とする必要があります

投稿2015/06/23 02:54

kutsulog

総合スコア985

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

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

dsk

2015/06/23 04:07

ご回答ありがとうございます。 なるほど、絞り込んだ時にすでに左に指定したテーブルからデータが抜け落ちていたということですね。 kutsulogさんにご指摘頂いた記述を加えた結果、得たいデータが得られました。 ありがとうございました。
guest

0

外部結合はそれぞれ、
left join は左に指定したテーブルから全レコードを取得
right join は右に指定したテーブルから全レコードを取得
します。

つまり、
tbl1 left join tbl2 では、左に指定したtbl1から全レコードを取得
tbl1 right join tbl2 では、右に指定したtbl2から全レコードを取得
します。

今回の場合、tbl1から全レコードを取得したいので、
tbl1 left join tbl2
とします。

投稿2015/06/23 01:38

編集2015/06/23 01:39
wakuwaku

総合スコア386

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

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

dsk

2015/06/23 02:29

ご回答ありがとうございました。 この場合はleft join が正しいとのことで、理解しました。 別の原因があるのではないかと思い、追記しましたので、よろしければご確認いただけましたら幸いです。
dsk

2015/06/23 04:31

ご指摘いただいたところとは別のところでも問題があったようでした。投稿時質問に書かれていなかった部分でした。申し訳ございません。無事解決しましたので報告させていただきます。左の評価の部分を上げることで、お礼とさせていただきます。ありがとうございました。
guest

0

inner join(内部結合)は指定された両方のテーブルから条件に合うものだけが抽出されます。
dskさんの望む形でデータを取得するには外部結合を用いる必要があります。

投稿2015/06/23 01:04

sho_cs

総合スコア3541

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

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

dsk

2015/06/23 01:28

ご回答ありがとうございます。質問文に追記させていただいたように、right join を試してみたのですが、結果に変化が見られませんでした。 別の問題がありますでしょうか。それとも書き方に問題がありますでしょうか。 何度もお手数をおかけします。よろしくお願いいたします。
dsk

2015/06/23 04:29

ご指摘いただいたところとは別のところでも問題があったようでした。投稿時質問に書かれていなかった部分でした。申し訳ございません。無事解決しましたので報告させていただきます。左の評価の部分を上げることで、お礼とさせていただきます。ありがとうございました。
guest

0

dskさんが使用しているinner joinが、二つのテーブルを対象とした場合、どちらか一方にNULLを含んだデータや、対応するデータが存在しない場合、結果が抽出されない結合だからです。
以下のアドレスを参考にし、left join または right joinを試してみてください。
NULLを含んだ列との結合(JOIN)【MySQL, PostgreSQL】

投稿2015/06/23 00:59

f-hanako

総合スコア159

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

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

dsk

2015/06/23 01:19

ご回答ありがとうございます。 教えていただいたように、left join と right join を試してみたのですが、同じ結果になってしまいました。 質問文も試したように変えてみたのですが、書き方が間違っていますでしょうか? 何度もお手数おかけします。 よろしくお願いいたします。
dsk

2015/06/23 04:28

ご指摘いただいたところとは別の問題があったようでした。投稿時質問に書かれていなかった部分でした。申し訳ございません。無事解決しましたので報告させていただきます。左の評価の部分を上げることで、お礼とさせていただきます。ありがとうございました。
dsk

2015/08/05 05:57 編集

×別の ○別のところでも でした。 何度もすみません。
guest

0

join 後のwhereで無くなっている可能性はありませんか?
試しに

lang

1select 2 product_name, 3 tbl2.total_sales, 4 to_char(tbl1.created, 'YYYY.MM.DD') as productcreated 5 6from tbl1 7left join tbl2 on tbl1.id = tbl2.product_id 8order by productcreated desc

の実行を行ってtotal_salesがNULLの値が取れるかを試してください。
取れる様でしたらwhere条件で省かれている可能性があります。

投稿2015/06/23 02:00

nanndemoiikara

総合スコア775

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

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

dsk

2015/06/23 02:27

ご回答ありがとうございます。 where句を抜いて left join した結果、nullが含まれる結果が返ってきました。 もしかすると、質問時記載していなかった別の条件指定が関係有るのかもしれないと思い追記2として情報を追加させていただきました。 こちらが関係しているのでしょうか。
nanndemoiikara

2015/06/23 04:06

コメントがかわいいです。 -- ★追記したもの★  ← -- ★追記したもの★ and tbl2.xxx = X and tbl2.yyy = Y この記述だとtbl2.yyyのカラムがYであるかつtbl2.xxxがXである必要があるのでNULLの値を取る事はできません。 IFNULL(tbl2.yyy, Y) = Y AND IFNULL(tbl2.xxx, X) = X このようにしてはいかがでしょうか?
nanndemoiikara

2015/06/23 04:07

kutsulog様のorでも問題ないので好みで使い分けられてはいかがでしょうか?
dsk

2015/06/23 04:22

何度もありがとうございます。(コメント、わかりやすく目立たせようと思ったのですが、可愛くなりすぎましたね。。笑) where product_name in ('aaaaa','bbbbbb','ccccccc','ddddd','eeeee','fffff','gggggg') and nullif(tbl2.xxx,X) = X and nullif(tbl2.yyy,Y) = Y where句のところを、上記のようにしてみましたが、検索結果が0になってしまいました。書き方が間違っていますでしょうか? *ifnull関数がないというエラーが出たので、調べてみたらnullifだとの事だったので書き換えてみました。 何度もお手数おかけしますが、教えていただければ幸いです。よろしくお願いいたします。
nanndemoiikara

2015/06/23 04:34

適当な事書いてすみませんでした。 postgresSQLにIFNULLがあると勘違いしてました。 NULLIFではなくCOALESCEではいかがでしょうか? Xが文字列 'string' と仮定した場合 COALESCE(tbl2.xxx, 'string') = 'string' といった形になります。 NULLIFだと第一引数と第二引数の値が同じ場合にNULLを返すようです。
dsk

2015/06/24 05:43 編集

いえいえ、ありがとうございます。 使ってみた結果、同様の結果が得られました。 kutsulogさんのやり方が、nullの場合も考慮に入れて検索するのに対し、 nanndemoiikaraさんのやり方は、nullを検索に引っかかるように変更するという感じでしょうか? 場合によって使い分けたいと思います。 いろいろと教えていただき、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問