ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
SQL 集合演算子とは
SQL の集合演算子 (Set Operator) は、2 つ以上の SELECT 文の結果集合を、数学的な集合演算(和・積・差)で結合する演算子です。標準 SQL では以下が定義されています:
| 演算子 | 意味 | 重複 |
|---|---|---|
| UNION | 和集合 (A ∪ B) | 排除 |
| UNION ALL | 和集合(重複保持) | 保持(高速) |
| INTERSECT | 積集合 (A ∩ B) | 排除 |
| INTERSECT ALL | 積集合(重複保持) | 保持 |
| EXCEPT / MINUS | 差集合 (A - B) | 排除 |
| EXCEPT ALL | 差集合(重複保持) | 保持 |
UNION と UNION ALL
-- 例: 社員テーブルと顧客テーブルから連絡先一覧
SELECT name, email FROM employees
UNION
SELECT name, email FROM customers
ORDER BY name;
-- UNION ALL: 重複行も含む(高速)
SELECT product_id FROM orders_2024
UNION ALL
SELECT product_id FROM orders_2025;
-- 性能差は大きい:
-- UNION → 結果に DISTINCT 相当の重複排除(ソート or ハッシュ)
-- UNION ALL → 単純連結のみ、ソート不要
-- → 重複が無いことが分かっているなら必ず UNION ALL
INTERSECT (積集合)
-- 例: メルマガと SMS 両方を購読している顧客
SELECT user_id FROM mailing_list
INTERSECT
SELECT user_id FROM sms_subscribers;
-- IN サブクエリでも同じことが書ける
SELECT user_id FROM mailing_list
WHERE user_id IN (SELECT user_id FROM sms_subscribers);
-- EXISTS バージョン
SELECT m.user_id FROM mailing_list m
WHERE EXISTS (SELECT 1 FROM sms_subscribers s WHERE s.user_id = m.user_id);
-- NULL の扱い:
-- 集合演算子は NULL = NULL と「同じ値」扱い
-- WHERE 句の = NULL は false 扱い → 注意
EXCEPT / MINUS (差集合)
-- 標準 SQL / PostgreSQL / SQL Server / MariaDB 10.3+
SELECT email FROM customers
EXCEPT
SELECT email FROM unsubscribed;
-- Oracle / DB2 (一部) は MINUS
SELECT email FROM customers
MINUS
SELECT email FROM unsubscribed;
-- 「顧客にいるがメルマガ未登録の人」
SELECT user_id FROM all_users
EXCEPT
SELECT user_id FROM mailing_list;
-- NOT IN / NOT EXISTS で書き換え
SELECT user_id FROM all_users
WHERE user_id NOT IN (SELECT user_id FROM mailing_list);
-- ⚠️ NULL が含まれると NOT IN は意図しない結果に
-- → NOT EXISTS の方が安全
SELECT u.user_id FROM all_users u
WHERE NOT EXISTS (SELECT 1 FROM mailing_list m WHERE m.user_id = u.user_id);
必要条件
| 条件 | 説明 |
|---|---|
| カラム数一致 | 各 SELECT のカラム数が同じ |
| データ型互換 | 対応位置のカラム型が同じ or 暗黙キャスト可 |
| カラム名 | 最初の SELECT の名前が結果に使われる |
| ORDER BY | 最後にのみ書ける。途中の SELECT には書けない |
| LIMIT | 同上(一部 DB で例外あり) |
-- ❌ カラム数不一致でエラー
SELECT id, name FROM a
UNION
SELECT id FROM b;
-- ORA-01789: query block has incorrect number of result columns
-- ❌ ORDER BY の位置エラー
SELECT name FROM a ORDER BY name
UNION
SELECT name FROM b;
-- → エラー
-- ✅ ORDER BY は最後
SELECT name FROM a
UNION
SELECT name FROM b
ORDER BY name;
-- ✅ 個別にソートしたい場合はサブクエリ
SELECT * FROM (SELECT name FROM a ORDER BY name LIMIT 10) sub1
UNION
SELECT * FROM (SELECT name FROM b ORDER BY name LIMIT 10) sub2;
CORRESPONDING (SQL 標準、実装少)
SQL 標準には UNION CORRESPONDING という構文があり、列名が一致する列だけで集合演算するものですが、多くの DB で未実装です(一部 DB2 のみ)。実用上はカラム順を揃えるのが定石。
NULL の扱い
-- 集合演算子では NULL = NULL として「同じ値」扱い
SELECT NULL FROM dual
INTERSECT
SELECT NULL FROM dual;
-- → 1 行 (NULL)
-- 通常の WHERE 句では NULL = NULL は UNKNOWN なので 0 行
-- これは set operator が DISTINCT 相当を内部実行する際の挙動
-- NULL を含むカラムは要注意
性能と Index
| 演算子 | 内部処理 | 性能 |
|---|---|---|
| UNION ALL | 連結のみ | 最速 |
| UNION | 連結 + Sort/Hash で重複排除 | 中 |
| INTERSECT | Hash Match or Sort Merge | 中 |
| EXCEPT / MINUS | Hash Match or Sort Merge | 中 |
各 SELECT 内で適切な Indexが効くようにすることが重要。集合演算子自体は最適化されにくいので、各 SELECT が高速に絞り込めるかが性能の鍵です。
各 DB の対応状況
| DB | UNION | INTERSECT | EXCEPT | MINUS |
|---|---|---|---|---|
| Oracle | ○ | ○ | × | ○ |
| PostgreSQL | ○ | ○ | ○ | × |
| SQL Server | ○ | ○ | ○ | × |
| MySQL 8.0+ | ○ | ○ (8.0.31+) | ○ (8.0.31+) | × |
| MySQL 5.7 | ○ | × (NOT EXISTS で代用) | × | × |
| MariaDB 10.3+ | ○ | ○ | ○ | ○ (10.6+ で同義) |
| SQLite | ○ | ○ | ○ | × |
| DB2 | ○ | ○ | ○ | × |
サブクエリ + EXISTS / NOT EXISTS との比較
-- (1) 集合演算子: 宣言的
SELECT user_id FROM a
INTERSECT
SELECT user_id FROM b;
-- (2) EXISTS: 手続き的
SELECT a.user_id FROM a
WHERE EXISTS (SELECT 1 FROM b WHERE b.user_id = a.user_id);
-- (3) JOIN: 直接結合
SELECT DISTINCT a.user_id FROM a
INNER JOIN b ON a.user_id = b.user_id;
-- 性能はオプティマイザ次第。多くの場合 (2) or (3) が速い
-- (1) は重複排除のソートコストがある
-- → 巨大データには (2) or (3) を検討
Materialized View での集合演算
-- 大規模 UNION ALL を Materialized View 化
CREATE MATERIALIZED VIEW all_orders AS
SELECT 'A' AS region, order_id, amount FROM orders_asia
UNION ALL
SELECT 'E' AS region, order_id, amount FROM orders_europe
UNION ALL
SELECT 'N' AS region, order_id, amount FROM orders_namerica;
-- リフレッシュ
REFRESH MATERIALIZED VIEW all_orders; -- PostgreSQL
EXEC DBMS_MVIEW.REFRESH('ALL_ORDERS'); -- Oracle
-- 統合ビューとして検索高速化
SELECT region, SUM(amount) FROM all_orders GROUP BY region;
実用例
パーティション分割テーブルの集約
-- 月別テーブルから 1 年分集計
SELECT order_id FROM orders_202501
UNION ALL SELECT order_id FROM orders_202502
UNION ALL SELECT order_id FROM orders_202503
...
UNION ALL SELECT order_id FROM orders_202512;
差分検出
-- 元テーブルと退避テーブルの差分
(SELECT * FROM master EXCEPT SELECT * FROM backup) -- 追加分
UNION ALL
(SELECT * FROM backup EXCEPT SELECT * FROM master); -- 削除分
FAQ
Q: UNION と JOIN の違いは?
A: UNION は縦方向の連結(行を増やす)、JOIN は横方向の結合(列を増やす)。全く別の操作です。
Q: UNION で「重複していない」と分かっていても UNION ALL に置き換えるべき?
A: はい。UNION は内部で DISTINCT 処理(ソート / ハッシュ)が走るため、不要なら UNION ALL の方が大幅に速いです。
Q: ORACLE の MINUS は ANSI SQL ?
A: いいえ、Oracle 独自構文です。標準 SQL は EXCEPT。Oracle 19c でも EXCEPT は未サポート(21c で追加予定)。
Q: MySQL 5.7 で INTERSECT が使いたい
A: MySQL 5.7 は未対応。INNER JOIN または EXISTS で書き換えてください。MySQL 8.0.31+ で正式対応しました。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- IPv6とは|128bitアドレス・コロン16進表記/::省略・リンクローカル・SLAAC・デュアルスタック NEW 2026-06-22 12:34:44
- VPNとは|暗号トンネル・サイト間/リモートアクセス・IPsec/SSL-VPN/WireGuardを解説 NEW 2026-06-22 12:19:10
- MAC アドレスフィルタリングの仕組みと限界 | ネットワーク入門 NEW 2026-06-22 12:19:10
- WebRTC とは ブラウザ間 P2P の音声・映像・データ通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- gRPC とは HTTP/2 + Protocol Buffers の高速 RPC | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/3 (QUIC) とは UDP ベースの低遅延 Web 通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/2 とは 多重化・HPACK・バイナリフレーム | ネットワーク入門 NEW 2026-06-22 12:17:25
- Web通信プロトコル入門 HTTP/2・HTTP/3・WebSocket・gRPC・WebRTC | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebSocket とは 全二重リアルタイム通信 ws/wss | ネットワーク入門 NEW 2026-06-22 12:17:25
- ファイアウォールとは|パケットフィルタ・ステートフル・DMZ・次世代FW(L4/L7)を解説 NEW 2026-06-22 12:17:24
- iptables/nftablesとは|テーブル・チェーン・ルール例・永続化をLinux視点で解説 NEW 2026-06-22 12:17:24
- HAProxy とは frontend/backend と設定例 | ネットワーク入門 NEW 2026-06-22 12:17:24
- 証明書と認証局(CA)とは|X.509・信頼チェーン・DV/OV/EV・失効(CRL/OCSP)を解説 NEW 2026-06-22 12:17:24
- CDN とは エッジキャッシュ・TTL・Cloudflare/CloudFront | ネットワーク入門 NEW 2026-06-22 12:17:24
- TLS/SSLの仕組み|ハンドシェイク・暗号スイート・前方秘匿性・証明書検証をわかりやすく解説 NEW 2026-06-22 12:17:24
コメントを削除してもよろしいでしょうか?