【Oracle SQL】外部結合でキーごとに1件のデータを抽出する方法!

どうも、しぐま(@sigma__blog )です!

この間、仕事でSQLを作成している中で苦戦したものがありました。

内容はタイトルの通りなのですが、詳細を言葉だけで説明するのが難しいので、テーブルのイメージも交えて説明します!

今回は下記の2テーブルを例に説明をします。

 

顧客テーブル(T_CUSTOMER)

CUST_IDCUST_NAMEAGE
0001山田 太郎20
0002山田 花子24
0003山田 香奈22

購入品テーブル(T_PURCHASED_ITEM)

CUST_IDPURCH_ITEMPRICEPURCH_DATE
0003バッグ70002019/04/02
0001カメラ1080002019/06/20
0002ペン2402019/02/04
0001シャツ30002019/04/01
0002時計120002019/03/17

この2テーブルを普通に外部結合すると、

CUST_IDCUST_NAMEPURCH_ITEMPRICE
0003山田 香奈バッグ7000
0001山田 太郎カメラ108000
0002山田 花子ペン240
0001山田 太郎シャツ3000
0002山田 花子時計12000

こうなりますよね。

書くまでもないですが一応、結合SQLはこちら。

 

それで、例えば顧客ごとに購入金額が最大のレコードのみを抽出したい、という場合はどのようにすればよいでしょうか。

結果イメージはこんな感じ。

CUST_IDCUST_NAMEPURCH_ITEMPRICE
0001山田 太郎カメラ108000
0002山田 花子時計12000
0003山田 香奈バッグ7000

 

僕が最初に試したのが次のSQLです。

結果はというと、「AND ROWNUM = 1」を付ける前のSQLと同じ結果が得られました。

どうやらROWNUMの指定は結合条件には意味が無いようです。

というか、これで仮にデータを1件抽出できたとしても、きっと「購入金額が最大のレコード」では無いですね(笑)

 

それではどうすればよいか。

まずは結果を先に載せておきます。

この「AND NOT EXISTS ~」の部分を解説すると、

まず、 「SELECT 1 FROM T_PURCHASED_ITEM C WHERE C.CUST_ID = A.CUST_ID」で結合に用いたT_PURCHASED_ITEM(B)と同じデータを用意し、結合キーの「CUST_ID」ごとにグルーピングします。

イメージはこんな感じ。(項目は解説の便宜上PRICEのみにしています)

■CUST_ID = ‘0001’

PRICE(Bテーブル)PRICE(Cテーブル)
108000108000
30003000

■CUST_ID = ‘0002’

PRICE(Bテーブル)PRICE(Cテーブル)
240240
1200012000

■CUST_ID = ‘0003’

PRICE(Bテーブル)PRICE(Cテーブル)
70007000

そして、このデータに対して「NOT EXISTS」「AND C.PRICE > B.PRICE」の条件をつけることで、「(グルーピングごとに)【BテーブルのPRICEよりCテーブルのPRICEの方が高価なものが】【存在しない】Bテーブルのレコード」を抽出しています!

BテーブルとCテーブルには同じデータが入っているので、結果的にBテーブルでPRICEが最大のレコードが取得できる。ということです!

また、PRICEの最小値を取得したい場合は条件部の符号を反転させればOKです!

NULLデータを考慮したい場合は「NVL」を使用して明示的に値を置き換えるのが良いと思います。

ではでは、今回はここまで!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です