PR

【SQL】UNION/UNION ALL わかりやすく3分で解説

Database

SQLにおける UNION/UNION ALL の使い方をデータベース初心者向けにわかりやすく3分で解説します。

UNION/UNION ALL はどちらもSELECT文で抽出した結果を統合する際に利用します。

SQL UNION ALL

このページでは初めてSQLを利用する方でも理解できるようにすべて図解付き・サンプルコード付きでご説明します。

このページで学べる内容
  • UNION の使い方
  • UNION ALL の使い方
  • UNION / UNION ALL の注意点

プログラマーやデータベースエンジニアを目指す方であれば知らないと恥ずかしい超・基本知識。是非最後までご覧ください。

スポンサーリンク

SQL:UNION

まずは、UNIONの使い方から解説します。

後ほど解説しますが、UNIONとUNION ALLの違いは以下の通り。

UNION vs UNION ALL
  • UNION:重複行を含めない(重複があったら除外して統合
  • UNION ALL:重複行を含む(重複があっても全て統合

SQL文のルール自体はほぼ同じなので、まずは基本的なUNIONの書き方から丁寧に学習していきましょう。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT カラム名 FROM テーブル名1
UNION
SELECT カラム名 FROM テーブル名2
SELECT カラム名 FROM テーブル名1 UNION SELECT カラム名 FROM テーブル名2
SELECT カラム名 FROM テーブル名1
UNION
SELECT カラム名 FROM テーブル名2

文法自体は非常に簡単でSELECT文UNIONで繋げるだけ。早速、実際にUNIONを利用したSQL文を実行していきましょう。

ここでは、以下のような2つのテーブルを利用します。

参考までに上記のMemberList_A/MemberList_Bテーブルを用意するためのCREATE TABLE文/INSERT文を掲載しておきます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
CREATE TABLE MemberList_A (
Number INT(2),
Name VARCHAR(50),
Class VARCHAR(1)
);
/*MemberList_A定義
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| Number | int(2) | YES | | NULL | |
| Name | varchar(50) | YES | | NULL | |
| Class | varchar(1) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
*/
CREATE TABLE MemberList_B (
Number INT(2),
Name VARCHAR(50),
Class VARCHAR(1)
);
/*MemberList_B定義
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| Number | int(2) | YES | | NULL | |
| Name | varchar(50) | YES | | NULL | |
| Class | varchar(1) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
*/
-- INSERT
INSERT INTO MemberList_A (Number,Name,Class) VALUES (1,'イチロウ','A');
INSERT INTO MemberList_A (Number,Name,Class) VALUES (2,'ジロウ','A');
INSERT INTO MemberList_A (Number,Name,Class) VALUES (3,'サブロウ','A');
INSERT INTO MemberList_A (Number,Name,Class) VALUES (4,'シロウ','A');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (1,'イチロウ','B');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (2,'ジロウ','B');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (3,'ゴロウ','B');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (4,'ハチロウ','B');
CREATE TABLE MemberList_A ( Number INT(2), Name VARCHAR(50), Class VARCHAR(1) ); /*MemberList_A定義 +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | Number | int(2) | YES | | NULL | | | Name | varchar(50) | YES | | NULL | | | Class | varchar(1) | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ */ CREATE TABLE MemberList_B ( Number INT(2), Name VARCHAR(50), Class VARCHAR(1) ); /*MemberList_B定義 +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | Number | int(2) | YES | | NULL | | | Name | varchar(50) | YES | | NULL | | | Class | varchar(1) | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ */ -- INSERT INSERT INTO MemberList_A (Number,Name,Class) VALUES (1,'イチロウ','A'); INSERT INTO MemberList_A (Number,Name,Class) VALUES (2,'ジロウ','A'); INSERT INTO MemberList_A (Number,Name,Class) VALUES (3,'サブロウ','A'); INSERT INTO MemberList_A (Number,Name,Class) VALUES (4,'シロウ','A'); INSERT INTO MemberList_B (Number,Name,Class) VALUES (1,'イチロウ','B'); INSERT INTO MemberList_B (Number,Name,Class) VALUES (2,'ジロウ','B'); INSERT INTO MemberList_B (Number,Name,Class) VALUES (3,'ゴロウ','B'); INSERT INTO MemberList_B (Number,Name,Class) VALUES (4,'ハチロウ','B');
CREATE TABLE MemberList_A (
Number       INT(2),
Name     VARCHAR(50),
Class    VARCHAR(1)
);

/*MemberList_A定義
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| Number | int(2)      | YES  |     | NULL    |       |
| Name   | varchar(50) | YES  |     | NULL    |       |
| Class  | varchar(1)  | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
*/


CREATE TABLE MemberList_B (
Number       INT(2),
Name     VARCHAR(50),
Class    VARCHAR(1)
);

/*MemberList_B定義
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| Number | int(2)      | YES  |     | NULL    |       |
| Name   | varchar(50) | YES  |     | NULL    |       |
| Class  | varchar(1)  | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
*/


-- INSERT
INSERT INTO MemberList_A (Number,Name,Class) VALUES (1,'イチロウ','A');
INSERT INTO MemberList_A (Number,Name,Class) VALUES (2,'ジロウ','A');
INSERT INTO MemberList_A (Number,Name,Class) VALUES (3,'サブロウ','A');
INSERT INTO MemberList_A (Number,Name,Class) VALUES (4,'シロウ','A');

INSERT INTO MemberList_B (Number,Name,Class) VALUES (1,'イチロウ','B');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (2,'ジロウ','B');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (3,'ゴロウ','B');
INSERT INTO MemberList_B (Number,Name,Class) VALUES (4,'ハチロウ','B');

この2つのテーブルから取得した結果を1つの結果として表示します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- UNION
SELECT Number,Name,Class FROM MemberList_A
UNION
SELECT Number,Name,Class FROM MemberList_B;
/* 結果
+--------+----------+-------+
| Number | Name | Class |
+--------+----------+-------+
| 1 | イチロウ | A |
| 2 | ジロウ | A |
| 3 | サブロウ | A |
| 4 | シロウ | A |
| 1 | イチロウ | B |
| 2 | ジロウ | B |
| 3 | ゴロウ | B |
| 4 | ハチロウ | B |
+--------+----------+-------+
*/
-- UNION SELECT Number,Name,Class FROM MemberList_A UNION SELECT Number,Name,Class FROM MemberList_B; /* 結果 +--------+----------+-------+ | Number | Name | Class | +--------+----------+-------+ | 1 | イチロウ | A | | 2 | ジロウ | A | | 3 | サブロウ | A | | 4 | シロウ | A | | 1 | イチロウ | B | | 2 | ジロウ | B | | 3 | ゴロウ | B | | 4 | ハチロウ | B | +--------+----------+-------+ */
-- UNION
SELECT Number,Name,Class FROM MemberList_A
UNION
SELECT Number,Name,Class FROM MemberList_B;

/* 結果
+--------+----------+-------+
| Number | Name     | Class |
+--------+----------+-------+
|      1 | イチロウ | A     |
|      2 | ジロウ   | A     |
|      3 | サブロウ | A     |
|      4 | シロウ   | A     |
|      1 | イチロウ | B     |
|      2 | ジロウ   | B     |
|      3 | ゴロウ   | B     |
|      4 | ハチロウ | B     |
+--------+----------+-------+
*/

2つのSELECT文の結果を1つのまとめて(統合して)取得することができました。

SELECT UNION ALL

この2つのテーブルはカラム数やデータ型が完全に一致しているので、以下のようにワイルドカードを利用しても問題ありません。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- UNION
SELECT * FROM MemberList_A
UNION
SELECT * FROM MemberList_B;
/* 結果
+--------+----------+-------+
| Number | Name | Class |
+--------+----------+-------+
| 1 | イチロウ | A |
| 2 | ジロウ | A |
| 3 | サブロウ | A |
| 4 | シロウ | A |
| 1 | イチロウ | B |
| 2 | ジロウ | B |
| 3 | ゴロウ | B |
| 4 | ハチロウ | B |
+--------+----------+-------+
*/
-- UNION SELECT * FROM MemberList_A UNION SELECT * FROM MemberList_B; /* 結果 +--------+----------+-------+ | Number | Name | Class | +--------+----------+-------+ | 1 | イチロウ | A | | 2 | ジロウ | A | | 3 | サブロウ | A | | 4 | シロウ | A | | 1 | イチロウ | B | | 2 | ジロウ | B | | 3 | ゴロウ | B | | 4 | ハチロウ | B | +--------+----------+-------+ */
-- UNION
SELECT * FROM MemberList_A
UNION
SELECT * FROM MemberList_B;

/* 結果
+--------+----------+-------+
| Number | Name     | Class |
+--------+----------+-------+
|      1 | イチロウ | A     |
|      2 | ジロウ   | A     |
|      3 | サブロウ | A     |
|      4 | シロウ   | A     |
|      1 | イチロウ | B     |
|      2 | ジロウ   | B     |
|      3 | ゴロウ   | B     |
|      4 | ハチロウ | B     |
+--------+----------+-------+
*/

また、カラムはテーブルのすべての列を指定する必要もないので、必要なカラムだけを指定することも可能です。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- UNION
SELECT Name,Class FROM MemberList_A
UNION
SELECT Name,Class FROM MemberList_B;
/* 結果
+----------+-------+
| Name | Class |
+----------+-------+
| イチロウ | A |
| ジロウ | A |
| サブロウ | A |
| シロウ | A |
| イチロウ | B |
| ジロウ | B |
| ゴロウ | B |
| ハチロウ | B |
+----------+-------+
*/
-- UNION SELECT Name,Class FROM MemberList_A UNION SELECT Name,Class FROM MemberList_B; /* 結果 +----------+-------+ | Name | Class | +----------+-------+ | イチロウ | A | | ジロウ | A | | サブロウ | A | | シロウ | A | | イチロウ | B | | ジロウ | B | | ゴロウ | B | | ハチロウ | B | +----------+-------+ */
-- UNION
SELECT Name,Class FROM MemberList_A
UNION
SELECT Name,Class FROM MemberList_B;

/* 結果
+----------+-------+
| Name     | Class |
+----------+-------+
| イチロウ | A     |
| ジロウ   | A     |
| サブロウ | A     |
| シロウ   | A     |
| イチロウ | B     |
| ジロウ   | B     |
| ゴロウ   | B     |
| ハチロウ | B     |
+----------+-------+
*/

SQL:UNION ALL

続いてUNION ALLについて解説します。UNIONとUNION ALLの違いは以下の通り。

UNION vs UNION ALL
  • UNION:重複行を含めない(重複があったら除外して統合
  • UNION ALL:重複行を含む(重複があっても全て統合

例えば、UNIONの場合は2つのSELECT文の結果に重複がある場合、以下のように重複行が除かれます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- SQL文
SELECT Number,Name FROM MemberList_A
UNION
SELECT Number,Name FROM MemberList_B;
/* 結果→重複行が除外
+--------+----------+
| Number | Name |
+--------+----------+
| 1 | イチロウ |
| 2 | ジロウ |
| 3 | サブロウ |
| 4 | シロウ |
| 3 | ゴロウ |
| 4 | ハチロウ |
+--------+----------+
*/
-- SQL文 SELECT Number,Name FROM MemberList_A UNION SELECT Number,Name FROM MemberList_B; /* 結果→重複行が除外 +--------+----------+ | Number | Name | +--------+----------+ | 1 | イチロウ | | 2 | ジロウ | | 3 | サブロウ | | 4 | シロウ | | 3 | ゴロウ | | 4 | ハチロウ | +--------+----------+ */
-- SQL文
SELECT Number,Name FROM MemberList_A
UNION
SELECT Number,Name FROM MemberList_B;

/* 結果→重複行が除外
+--------+----------+
| Number | Name     |
+--------+----------+
|      1 | イチロウ |
|      2 | ジロウ   |
|      3 | サブロウ |
|      4 | シロウ   |
|      3 | ゴロウ   |
|      4 | ハチロウ |
+--------+----------+
*/
SQL UNION

2つのSELECT文の結果の両方に含まれるNumber1~2のレコードが除外されて統合されています。

一方でUNION ALLを利用すれば重複している行が除外されずに出力されます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- SQL文(UNION ALL)
SELECT Number,Name FROM MemberList_A
UNION ALL
SELECT Number,Name FROM MemberList_B;
/* 結果→重複行は除外されない
+--------+----------+
| Number | Name |
+--------+----------+
| 1 | イチロウ |
| 2 | ジロウ |
| 3 | サブロウ |
| 4 | シロウ |
| 1 | イチロウ |
| 2 | ジロウ |
| 3 | ゴロウ |
| 4 | ハチロウ |
+--------+----------+
*/
-- SQL文(UNION ALL) SELECT Number,Name FROM MemberList_A UNION ALL SELECT Number,Name FROM MemberList_B; /* 結果→重複行は除外されない +--------+----------+ | Number | Name | +--------+----------+ | 1 | イチロウ | | 2 | ジロウ | | 3 | サブロウ | | 4 | シロウ | | 1 | イチロウ | | 2 | ジロウ | | 3 | ゴロウ | | 4 | ハチロウ | +--------+----------+ */
-- SQL文(UNION ALL)
SELECT Number,Name FROM MemberList_A
UNION ALL
SELECT Number,Name FROM MemberList_B;

/* 結果→重複行は除外されない
+--------+----------+
| Number | Name     |
+--------+----------+
|      1 | イチロウ |
|      2 | ジロウ   |
|      3 | サブロウ |
|      4 | シロウ   |
|      1 | イチロウ |
|      2 | ジロウ   |
|      3 | ゴロウ   |
|      4 | ハチロウ |
+--------+----------+
*/
UNION ALL

UNION ALLとUNIONの使い分けは簡単なのですが、プログラムを実装していく上では誤りが出やすいポイントでもあります。

よく注意して覚えておきましょう!

UNION/UNION ALLの注意点

文法上はどちらも非常に簡単なのですが、注意点が3点存在します。

最後にこの3つの注意点を解説します。

UNION/UNION ALLの注意点
  • ①:指定するカラムの数は同じにすること
  • ②:指定するカラムのデータ型が一致していること
  • ③:ORDER BY句は最後に1つだけ利用すること

UNION―注意点1:指定するカラムの数は同じにすること

UNION/UNION ALLでは、指定するカラムの数が必ず一致している必要があります。

例えば、以下のSQLは2つのSELECT文で指定しているレコード数が異なるためエラーが発生します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- エラーが発生するパターン1
SELECT Number,Name,Class FROM MemberList_A
UNION
SELECT Number,Name FROM MemberList_B;
--ERROR 1222 (21000): The used SELECT statements have a different number of columns
-- エラーが発生するパターン1 SELECT Number,Name,Class FROM MemberList_A UNION SELECT Number,Name FROM MemberList_B; --ERROR 1222 (21000): The used SELECT statements have a different number of columns
-- エラーが発生するパターン1
SELECT Number,Name,Class FROM MemberList_A
UNION
SELECT Number,Name FROM MemberList_B;

--ERROR 1222 (21000): The used SELECT statements have a different number of columns

逆に言えば、指定するカラムの数が一致していれば以下のようなSQLは正常に動作します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT Number,Name FROM MemberList_A
UNION
SELECT Number,Class FROM MemberLIst_B;
/* 結果
+--------+----------+
| Number | Name |
+--------+----------+
| 1 | イチロウ |
| 2 | ジロウ |
| 3 | サブロウ |
| 4 | シロウ |
| 1 | B |
| 2 | B |
| 3 | B |
| 4 | B |
+--------+----------+
*/
SELECT Number,Name FROM MemberList_A UNION SELECT Number,Class FROM MemberLIst_B; /* 結果 +--------+----------+ | Number | Name | +--------+----------+ | 1 | イチロウ | | 2 | ジロウ | | 3 | サブロウ | | 4 | シロウ | | 1 | B | | 2 | B | | 3 | B | | 4 | B | +--------+----------+ */
SELECT Number,Name FROM MemberList_A
UNION
SELECT Number,Class FROM MemberLIst_B;

/* 結果
+--------+----------+
| Number | Name     |
+--------+----------+
|      1 | イチロウ |
|      2 | ジロウ   |
|      3 | サブロウ |
|      4 | シロウ   |
|      1 | B        |
|      2 | B        |
|      3 | B        |
|      4 | B        |
+--------+----------+
*/

1つ目のSQL文で指定したカラム名に沿う形で結果が統合されていることが分かります。

UNION―注意点2:指定するカラムのデータ型が一致していること

注意点の2つ目が「データ型」です。指定するカラム(=左から数えて同じ位置にあるカラム)のデータ型は一致している必要があります。

例えば、以下のようなSQLはエラーになります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT Number FROM MemberList_A
UNION
SELECT Class FROM MemberLIst_B;
/*
Number →INT型
Class →Varchar型
*/
SELECT Number FROM MemberList_A UNION SELECT Class FROM MemberLIst_B; /* Number →INT型 Class →Varchar型 */
SELECT Number FROM MemberList_A
UNION
SELECT Class FROM MemberLIst_B;

/* 
Number →INT型
Class  →Varchar型
*/

ただし、利用するDBMSによっては気を利かせてデータ型の変換を暗黙的に行い、結果が取得できる場合があります。

例えば、MySQLでは以下のようにエラーは発生せずに結果が返って来ます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT Number FROM MemberList_A
UNION
SELECT Class FROM MemberLIst_B;
/* 結果は正常に返ってくる
+--------+
| Number |
+--------+
| 1 |
| 2 |
| 3 |
| 4 |
| B |
+--------+
*/
SELECT Number FROM MemberList_A UNION SELECT Class FROM MemberLIst_B; /* 結果は正常に返ってくる +--------+ | Number | +--------+ | 1 | | 2 | | 3 | | 4 | | B | +--------+ */
SELECT Number FROM MemberList_A
UNION
SELECT Class FROM MemberLIst_B;

/* 結果は正常に返ってくる
+--------+
| Number |
+--------+
| 1      |
| 2      |
| 3      |
| 4      |
| B      |
+--------+
*/

ただし、利用するDBMSによっては暗黙的にデータ型の変換を行わない場合もあるため「原則的にはデータ型の一致は必須である」と理解しておくのが良いでしょう。

UNION―注意点3:ORDER BY句は最後に1つだけ利用すること

UNIONを利用するSQL文では、ORDER BY句は全体の最後に一度だけしか利用できないという注意点があります。

例えば、以下のSQL文では、ORDER BY句をそれぞれのSELECT文の中で利用しているためエラーが発生します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT Number,Name FROM MemberList_A
ORDER BY Number
UNION ALL
SELECT Number,Name FROM MemberList_B
ORDER BY Number;
-- ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY
SELECT Number,Name FROM MemberList_A ORDER BY Number UNION ALL SELECT Number,Name FROM MemberList_B ORDER BY Number; -- ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY
SELECT Number,Name FROM MemberList_A
ORDER BY Number
UNION ALL
SELECT Number,Name FROM MemberList_B
ORDER BY Number;

-- ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY

正しい文法では、以下のように全体の最後に1度だけ利用します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT Number,Name FROM MemberList_A
UNION ALL
SELECT Number,Name FROM MemberList_B
ORDER BY Number;
/* 正常に結果が取得できる
+--------+----------+
| Number | Name |
+--------+----------+
| 1 | イチロウ |
| 1 | イチロウ |
| 2 | ジロウ |
| 2 | ジロウ |
| 3 | サブロウ |
| 3 | ゴロウ |
| 4 | ハチロウ |
| 4 | シロウ |
+--------+----------+
*/
SELECT Number,Name FROM MemberList_A UNION ALL SELECT Number,Name FROM MemberList_B ORDER BY Number; /* 正常に結果が取得できる +--------+----------+ | Number | Name | +--------+----------+ | 1 | イチロウ | | 1 | イチロウ | | 2 | ジロウ | | 2 | ジロウ | | 3 | サブロウ | | 3 | ゴロウ | | 4 | ハチロウ | | 4 | シロウ | +--------+----------+ */
SELECT Number,Name FROM MemberList_A
UNION ALL
SELECT Number,Name FROM MemberList_B
ORDER BY Number;

/* 正常に結果が取得できる
+--------+----------+
| Number | Name     |
+--------+----------+
|      1 | イチロウ |
|      1 | イチロウ |
|      2 | ジロウ   |
|      2 | ジロウ   |
|      3 | サブロウ |
|      3 | ゴロウ   |
|      4 | ハチロウ |
|      4 | シロウ   |
+--------+----------+
*/
UNION/UNION ALL のまとめ
  • UNION/UNION ALL・・・結果を統合して取得
    • UNION:重複行を含めない(重複があったら除外して統合
    • UNION ALL:重複行を含む(重複があっても全て統合
  • UNION/UNION ALLの注意点
    • ①:指定するカラムの数は同じにすること
    • ②:指定するカラムのデータ型が一致していること
    • ③:ORDER BY句は最後に1つだけ利用することSQL UNION ALL
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT カラム名 FROM テーブル名1
UNION
SELECT カラム名 FROM テーブル名2
SELECT カラム名 FROM テーブル名1 UNION SELECT カラム名 FROM テーブル名2
SELECT カラム名 FROM テーブル名1
UNION
SELECT カラム名 FROM テーブル名2

システムエンジニアを目指したい方は

システムエンジニアを目指す方や、IT知識を1から身につけたい方は以下のページをご覧ください。

正直どこから学び始めればよいかわからない。どのように勉強していけば、エンジニアとしてのスキルが磨けるか?が分からない・・・という方は必見です。

タイトルとURLをコピーしました