SELECT ...
UNION [ALL | DISTINCT] SELECT ...
[UNION [ALL | DISTINCT] SELECT ...]
UNION
は、複数の SELECT
ステートメントの結果を単一の結果セットに結合します。 例:
mysql> SELECT 1, 2;
+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
+---+---+
mysql> SELECT 'a', 'b';
+---+---+
| a | b |
+---+---+
| a | b |
+---+---+
mysql> SELECT 1, 2 UNION SELECT 'a', 'b';
+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
| a | b |
+---+---+
結果セットのカラム名およびデータ型
UNION
結果セットのカラム名は、最初の SELECT
ステートメントのカラム名から取得されます。
各 SELECT
ステートメントの対応する位置にリストされている選択されるカラムは、データ型が同じになるようにしてください。 たとえば、最初のステートメントで選択された最初のカラムは、他のステートメントで選択された最初のカラムと同じタイプである必要があります。 対応する SELECT
カラムのデータ型が一致しない場合、UNION
結果のカラムの型と長さでは、すべての SELECT
ステートメントによって取得された値が考慮されます。 たとえば、カラムの長さが最初の SELECT
の値の長さに制約されていない次の例を考えてみます:
mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',20);
+----------------------+
| REPEAT('a',1) |
+----------------------+
| a |
| bbbbbbbbbbbbbbbbbbbb |
+----------------------+
共用体の TABLE
MySQL 8.0.19 以降では、同等の SELECT
ステートメントを使用できる場所であれば、UNION
で TABLE
ステートメントまたは VALUES
ステートメントを使用することもできます。 次に示すように、テーブル t1
および t2
が作成され、移入されているとします:
CREATE TABLE t1 (x INT, y INT);
INSERT INTO t1 VALUES ROW(4,-2),ROW(5,9);
CREATE TABLE t2 (a INT, b INT);
INSERT INTO t2 VALUES ROW(1,2),ROW(3,4);
前述の例では、VALUES
以降のクエリーの出力のカラム名は無視され、次の UNION
クエリーはすべて同じ結果になります:
SELECT * FROM t1 UNION SELECT * FROM t2;
TABLE t1 UNION SELECT * FROM t2;
VALUES ROW(4,-2), ROW(5,9) UNION SELECT * FROM t2;
SELECT * FROM t1 UNION TABLE t2;
TABLE t1 UNION TABLE t2;
VALUES ROW(4,-2), ROW(5,9) UNION TABLE t2;
SELECT * FROM t1 UNION VALUES ROW(4,-2),ROW(5,9);
TABLE t1 UNION VALUES ROW(4,-2),ROW(5,9);
VALUES ROW(4,-2), ROW(5,9) UNION VALUES ROW(4,-2),ROW(5,9);
カラム名を強制的に同じにするには、VALUES
を SELECT
の左側にラップし、次のようにエイリアスを使用します:
SELECT * FROM (VALUES ROW(4,-2), ROW(5,9)) AS t(x,y)
UNION TABLE t2;
SELECT * FROM (VALUES ROW(4,-2), ROW(5,9)) AS t(x,y)
UNION VALUES ROW(4,-2),ROW(5,9);
UNION DISTINCT および UNION ALL
デフォルトでは、重複行は UNION
の結果から削除されます。 オプションの DISTINCT
キーワードも同じ効果がありますが、明示的になります。 オプションの ALL
キーワードを指定すると、重複した行の削除は実行されず、その結果には、すべての SELECT
ステートメントからの一致するすべての行が含まれます。
UNION ALL
と UNION DISTINCT
を同じクエリー内で混在させることができます。 混在した UNION
型は、DISTINCT
和集合がその左側にある ALL
和集合をすべてオーバーライドするように処理されます。 DISTINCT
和集合は、UNION DISTINCT
を使用して明示的に、あるいはそのあとに DISTINCT
または ALL
キーワードのない UNION
を使用して暗黙的に生成できます。
MySQL 8.0.19 以降では、UNION ALL
および UNION DISTINCT
は、1 つ以上の TABLE
ステートメントが共用体で使用されている場合と同じように動作します。
UNION での ORDER BY および LIMIT
ORDER BY
または LIMIT
句を個々の SELECT
に適用するには、SELECT
をカッコで囲み、カッコ内に句を配置します:
(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
個々の SELECT
ステートメントに ORDER BY
を使用すると、UNION
では順序付けられていない行のセットがデフォルトで生成されるため、最終結果に行が表示される順序については何も意味しません。 したがって、このコンテキストの ORDER BY
は通常、SELECT
用に取得する選択済の行のサブセットを決定するために LIMIT
とともに使用されますが、最終的な UNION
結果の行の順序には必ずしも影響しません。 SELECT
に LIMIT
がない状態で ORDER BY
が表示された場合は、どのような場合にも効果がないため最適化されます。
ORDER BY
または LIMIT
句を使用して UNION
結果全体をソートまたは制限するには、個々の SELECT
ステートメントをカッコで囲み、最後のステートメントの後に ORDER BY
または LIMIT
を配置します:
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;
括弧のないステートメントは、今示した括弧で囲まれたステートメントと同等です。
MySQL 8.0.19 以降、TABLE
は WHERE
句をサポートしていないことに注意して、前述の方法と同じ方法で TABLE
とともに ORDER BY
および LIMIT
を使用できます。
この種の ORDER BY
は、テーブル名 (つまり、tbl_name
.col_name
という形式の名前) を含むカラム参照を使用できません。 代わりに、最初の SELECT
ステートメント内にカラムのエイリアスを指定し、そのエイリアスを ORDER BY
内で参照します。 (あるいは、ORDER BY
内でカラムを、そのカラム位置を使用して参照します。 ただし、カラム位置の使用は非推奨です。)
また、ソートされるカラムにエイリアスが指定されている場合、ORDER BY
句はそのカラム名ではなく、エイリアスを参照する必要があります。 次のステートメントのうち最初のステートメントは許可されていますが、次のステートメントは Unknown column 'a' in 'order clause'
エラーで失敗します:
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b;
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;
UNION
結果の行が各 SELECT
によって取得された行のセットで構成されるようにするには、ソートカラムとして使用する各 SELECT
の追加のカラムを選択し、最後の SELECT
に続くそのカラムでソートする ORDER BY
を追加します:
(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1)
UNION
(SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col;
さらに個々の SELECT
の結果内のソート順序を維持するには、ORDER BY
句にセカンダリカラムを追加します。
(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1)
UNION
(SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col, col1a;
また、追加のカラムを使用すると、各行がどの SELECT
から取得されるかを決定することもできます。 追加のカラムでは、テーブル名を示す文字列などのほかの識別情報も指定できます。
UNION の制限
UNION
では、SELECT
ステートメントは通常の SELECT ステートメントですが、次の制限があります:
最初の
SELECT
のHIGH_PRIORITY
は効果がありません。 後続のSELECT
のHIGH_PRIORITY
では、構文エラーが発生します。最後の
SELECT
ステートメントのみがINTO
句を使用できます。 ただし、UNION
の結果全体がINTO
出力先に書き込まれます。
MySQL 8.0.20 では、INTO
を含む次の 2 つの UNION
バリアントは非推奨であり、将来のバージョンの MySQL でサポートが削除される予定です:
-
クエリー式の後続のクエリーブロックでは、
FROM
の前にINTO
を使用すると警告が生成されます。 例:... UNION SELECT * INTO OUTFILE 'file_name' FROM table_name;
-
クエリー式のカッコで囲まれた後続ブロックでは、
INTO
を (FROM
に対する相対位置に関係なく) 使用すると警告が生成されます。 例:... UNION (SELECT * INTO OUTFILE 'file_name' FROM table_name);
これらのバリアントは、クエリー式 (
UNION
) 全体ではなく名前付きテーブルから情報を収集するかのように、混乱しているため非推奨です。
ORDER BY
句に集計関数を含む UNION
クエリーは、ER_AGGREGATE_ORDER_FOR_UNION
エラーで拒否されます。 例:
SELECT 1 AS foo UNION SELECT 2 ORDER BY MAX(1);
MySQL 5.7 と比較した MySQL 8.0 での UNION の処理
MySQL 8.0 では、SELECT
および UNION
のパーサールールがリファクタリングされ、より一貫性が保たれ (このような各コンテキストで同じ SELECT
構文が均一に適用される)、重複が削減されました。 MySQL 5.7 と比較すると、この作業の結果、次のようないくつかのユーザーに見える影響があり、特定のステートメントのリライトが必要になる場合があります:
NATURAL JOIN
では、標準 SQL に準拠したオプションのINNER
キーワード (NATURAL INNER JOIN
) を使用できます。標準 SQL に準拠すると、カッコなしの右重複結合 (
... JOIN ... JOIN ... ON ... ON
など) が許可されます。STRAIGHT_JOIN
では、他の内部結合と同様にUSING
句が許可されるようになりました。パーサーは、クエリー式を囲むカッコを受け入れます。 たとえば、
(SELECT ... UNION SELECT ...)
は許可されています。 セクション13.2.10.4「カッコで囲まれたクエリー式」も参照してください。パーサーは、
SQL_CACHE
およびSQL_NO_CACHE
クエリー修飾子の許可された配置に準拠しています。-
以前はサブクエリーでのみ許可されていた共用体の左端のネストが、トップレベルのステートメントで許可されるようになりました。 たとえば、次のステートメントは有効として受け入れられます:
(SELECT 1 UNION SELECT 1) UNION SELECT 1;
-
ロック句 (
FOR UPDATE
、LOCK IN SHARE MODE
) は、UNION
以外のクエリーでのみ使用できます。 つまり、ロック句を含むSELECT
ステートメントにはカッコを使用する必要があります。 このステートメントは有効ではなくなりました:SELECT 1 FOR UPDATE UNION SELECT 1 FOR UPDATE;
かわりに、次のようなステートメントを記述します:
(SELECT 1 FOR UPDATE) UNION (SELECT 1 FOR UPDATE);