ray88’s diary

お仕事で困ったとき用の自分用の覚書

SQL 片方のテーブルにしか存在しないデータの抽出と結合

■自己結合を利用した片方のテーブルにしか存在しないデータの抽出
【例題】
以下のカラムを持つテーブルがあります。
グループID、グループ名、メンバ数、ユーザID、ユーザ名
1つのテーブルから以下2つのレコードをそれぞれ抽出して比較し、縦に結合したい。
1つのSQL文でこれを実現する。
 抽出したいレコード
 レコード1:グループ名がDefaultの値以外のレコード
 レコード2:「グループ名の値がDefault」かつ「レコード1にユーザIDが存在しない」レコード
 レコード1とレコード2を縦に結合したい

【パターン1】WITH句の利用

WITH Record1 AS (
    SELECT *
    FROM your_table_name
    WHERE group_name <> 'Default'
),

Record2 AS (
    SELECT *
    FROM your_table_name t1
    WHERE t1.group_name = 'Default'
    AND NOT EXISTS (
        SELECT 1
        FROM Record1 t2
        WHERE t1.user_id = t2.user_id
    )
)

SELECT * FROM Record1
UNION ALL
SELECT * FROM Record2;

解説:上記のSQL文では、まずWITH句を使用して2つのサブクエリを定義しています:
Record1: グループ名がDefault以外のレコードを抽出するサブクエリ。
Record2: グループ名がDefaultで、かつRecord1に存在しないユーザIDのレコードを抽出するサブクエリ。
最後に、UNION ALLを使用して、Record1とRecord2の結果を縦に結合しています。
このSQL文を実行すると、指定された条件に基づいてレコードが縦に結合された結果が得られます。
注: 上記のSQL文では、テーブル名をyour_table_nameとしています。実際のテーブル名に置き換えて使用してください。

【パターン2】UNION ALLを利用

SELECT *
FROM your_table_name
WHERE group_name <> 'Default'

UNION ALL

SELECT t1.*
FROM your_table_name t1
LEFT JOIN your_table_name t2 ON t1.user_id = t2.user_id AND t2.group_name <> 'Default'
WHERE t1.group_name = 'Default' AND t2.user_id IS NULL;

解説:上記のSQLでは、LEFT JOINを使用して、Defaultでないグループ名を持つレコードが存在しないDefaultのグループ名を持つレコードを抽出しています。その後、UNION ALLを使用して、2つの結果セットを縦に結合しています。