【SQL】SQL ~ 関係演算 / 集合論 ~

■ はじめに

SQL で前から集合ってことは知っていたが、
「基本がわかるSQL入門」って本で、
ちゃんと書かれていたので、メモ。

* Snowflake については、以下の関連記事を参照のこと

Snowflake ~ 関係演算 / 集合論
https://dk521123.hatenablog.com/entry/2024/09/12/003814

目次

【1】使用データ
【2】SQLで集合演算をする際の注意点
 1)2つのテーブルのカラムが揃っている必要がある
【3】和(union)
【4】差(difference)
【5】共通(intersection)
【6】直積(direct product)
【7】選択(selection)
【8】射影(projection)
【9】結合(Join)
【10】商(division)

【1】使用データ

* PostgreSQL17を想定

https://www.db-fiddle.com/

データ定義

CREATE TABLE member (
  id       INT,
  name     VARCHAR(50),
  tel    VARCHAR(30),
  updated_date    DATE
);

CREATE TABLE staff (
  id       INT,
  name     VARCHAR(50),
  tel    VARCHAR(30),
  updated_date    DATE
);

使用データ

INSERT INTO member (id,name,tel,updated_date) VALUES
  (1,'Mike','1234567890','2024-09-14'),
  (2,'Tom',NULL,'2024-09-14'),
  (3,'Smith','1111111111','2024-09-14'),
  (4,'Ken',NULL,'2024-09-14')
;

INSERT INTO staff(id,name,tel,updated_date) VALUES
  (1,'Tom',NULL,'2024-10-15'),
  (2,'Ken',NULL,'2024-10-15'),
  (3,'Henry','66666666','2024-10-15'),
  (4,'George','3333333333333','2024-10-14'),
  (5,'Jack','22222222222','2024-10-14')
;

【2】SQLで集合演算をする際の注意点

1)2つのテーブルのカラムが揃っている必要がある

-- OK:id で揃っている
SELECT id FROM member
UNION ALL
SELECT id FROM staff;

-- NG:memberはid, nameだが、staffはid
SELECT id, name FROM member
UNION ALL
SELECT id FROM staff;

【3】和(union)

* 2つ又は3つ以上の集合の全要素を集めること

1)SQL

* 和演算は、UNIONを使う
* 重複行をそのまま残す場合は、UNION ALL
 => Union / Union All については、以下の関連記事を参照のこと

テーブルの結合 ~完全結合・Union / Union All ~
https://dk521123.hatenablog.com/entry/2010/03/28/162247

2)サンプル

SELECT name, tel FROM member
UNION
SELECT name, tel FROM staff
ORDER BY name, tel
;
name tel
George 3333333333333
Henry 66666666
Jack 22222222222
Ken
Mike 1234567890
Smith 1111111111
Tom
-- 重複行をそのまま残す場合は、UNION ALL (Ken/Tomに注目)
SELECT name, tel FROM member
UNION ALL
SELECT name, tel FROM staff
ORDER BY name, tel
;
name tel
George 3333333333333
Henry 66666666
Jack 22222222222
Ken
Ken
Mike 1234567890
Smith 1111111111
Tom
Tom

【4】差(difference)

* 2つの集合で、
 1つ目の集合にはあるけど、
 2つ目の集合にはない

1)SQL

* 差演算は、EXCEPT / MINUS を使う
* 重複行をそのまま残す場合は、EXCEPT ALL
 =>EXCEPT / MINUS については、以下の関連記事を参照のこと

差集合 ~ EXCEPT / MINUS etc ~
https://dk521123.hatenablog.com/entry/2021/05/26/142059

EXCEPT非対応DBの場合

* MySQLなど、EXCEPT / EXCEPT ALL がないDBの場合
 => 外部結合 又は サブクエリを使う

2)サンプル

SELECT name, tel FROM member
EXCEPT
SELECT name, tel FROM staff
ORDER BY name, tel
;
name tel
Mike 1234567890
Smith 1111111111

EXCEPT非対応DBの場合

-- 外部結合
SELECT m.name, m.tel FROM member as m
LEFT JOIN staff as s
 ON m.name = s.name AND m.tel = s.tel
WHERE s.name IS NULL;
name tel
Mike 1234567890
Tom
Smith 1111111111
Ken
-- サブクエリ
SELECT m.name, m.tel FROM member as m
WHERE NOT EXISTS (
  SELECT * FROM staff as s
  WHERE m.name = s.name AND m.tel = s.tel
);
name tel
Mike 1234567890
Tom
Smith 1111111111
Ken

【5】共通(intersection)

* 2つ又は3つ以上の集合で、同じ要素を求める
 => A と B という集合があった場合、
  その共通部分を算出する(積集合)

1)SQL

* INTERSECT を使う
* 重複行をそのまま残す場合は、INTERSECT ALL

SQL ~ INTERSECT ~
https://dk521123.hatenablog.com/entry/2024/09/14/040940

INTERSECT 非対応DBの場合

* 内部結合、サブクエリ、IN句などを使用

2)サンプル

SELECT name, tel FROM member
INTERSECT 
SELECT name, tel FROM staff
ORDER BY name, tel
;
name tel
Ken
Tom

【6】直積(direct product)

* 2つ又は3つ以上の集合を掛け合わせる

1)SQL

* CROSS JOIN を使う
 => CROSS JOIN に関しては、以下の関連記事を参照のこと

テーブル結合 ~ 交差結合・CROSS JOIN ~
https://dk521123.hatenablog.com/entry/2011/12/21/000000

CROSS JOIN 非対応DBの場合

* FROM句に複数テーブルを指定し
 結合条件を書かなければいい

2)サンプル

SELECT * FROM member CROSS JOIN staff;

-- FROM句に複数テーブルを指定
SELECT * FROM member, staff;
id name tel updated_date id name tel updated_date
1 Mike 1234567890 2024-09-14 1 Tom 2024-10-15
1 Mike 1234567890 2024-09-14 2 Ken 2024-10-15
1 Mike 1234567890 2024-09-14 3 Henry 66666666 2024-10-15
1 Mike 1234567890 2024-09-14 4 George 3333333333333 2024-10-14
1 Mike 1234567890 2024-09-14 5 Jack 22222222222 2024-10-14
2 Tom 2024-09-14 1 Tom 2024-10-15
2 Tom 2024-09-14 2 Ken 2024-10-15
2 Tom 2024-09-14 3 Henry 66666666 2024-10-15
2 Tom 2024-09-14 4 George 3333333333333 2024-10-14
2 Tom 2024-09-14 5 Jack 22222222222 2024-10-14
3 Smith 1111111111 2024-09-14 1 Tom 2024-10-15
3 Smith 1111111111 2024-09-14 2 Ken 2024-10-15
3 Smith 1111111111 2024-09-14 3 Henry 66666666 2024-10-15
3 Smith 1111111111 2024-09-14 4 George 3333333333333 2024-10-14
3 Smith 1111111111 2024-09-14 5 Jack 22222222222 2024-10-14
4 Ken 2024-09-14 1 Tom 2024-10-15
4 Ken 2024-09-14 2 Ken 2024-10-15
4 Ken 2024-09-14 3 Henry 66666666 2024-10-15
4 Ken 2024-09-14 4 George 3333333333333 2024-10-14
4 Ken 2024-09-14 5 Jack 22222222222 2024-10-14

【7】選択(selection)

* ある条件を満足させる行を選び取る場合

1)SQL

* WHEREを使う(そんだけ)

2)サンプル

SELECT * FROM member WHERE name='Mike';
id name tel updated_date
1 Mike 1234567890 2024-09-14

【8】射影(projection)

* 属性の部分集合から別の表を作ること

1)SQL

* SELECT句で列を指定する(そんだけ)

2)サンプル

SELECT name FROM member;
name
Mike
Tom
Smith
Ken

【9】結合(Join)

* 一方の表が他方の表を完全に含む要素だけを取り出す演算

1)SQL

* INNER JOINを使う(そんだけ)

2)サンプル

SELECT * FROM member as m
INNER JOIN staff as s
ON m.id = s.id
;
id name tel updated_date id name tel updated_date
1 Mike 1234567890 2024-09-14 1 Tom 2024-10-15
2 Tom 2024-09-14 2 Ken 2024-10-15
3 Smith 1111111111 2024-09-14 3 Henry 66666666 2024-10-15
4 Ken 2024-09-14 4 George 3333333333333 2024-10-14

【10】商(division)

* 一方の表が他方の表を完全に含む要素だけを取り出す演算

1)SQL

* サブクエリを2つ組み合わせて実現

関連記事

SQLを書くコツ
https://dk521123.hatenablog.com/entry/2016/01/11/173055
相関サブクエリ / 自己相関サブクエリ
https://dk521123.hatenablog.com/entry/2016/01/23/230608
差集合 ~ EXCEPT / MINUS etc ~
https://dk521123.hatenablog.com/entry/2021/05/26/142059
SQL ~ INTERSECT ~
https://dk521123.hatenablog.com/entry/2024/09/14/040940
テーブルの結合 ~内部結合・INNER JOIN~
https://dk521123.hatenablog.com/entry/2010/02/05/131206
テーブルの結合 ~ 外部結合・LEFT/RIGHT/FULL JOIN ~
https://dk521123.hatenablog.com/entry/2012/05/06/212246
テーブル結合 ~ 交差結合・CROSS JOIN ~
https://dk521123.hatenablog.com/entry/2011/12/21/000000
テーブルの結合 ~完全結合・Union / Union All ~
https://dk521123.hatenablog.com/entry/2010/03/28/162247
全く関係ないテーブルを結合することを考える
https://dk521123.hatenablog.com/entry/2021/09/16/185552
Snowflake ~ 関係演算 / 集合論
https://dk521123.hatenablog.com/entry/2024/09/12/003814
SQL ~ 集合演算の応用 ~
https://dk521123.hatenablog.com/entry/2024/09/16/223305
SQL ~ テーブル差分を調査することを考える ~
https://dk521123.hatenablog.com/entry/2024/09/22/220455
Window関数 ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/02/22/000000