MySQL 8.0 リファレンスマニュアル


13.2.10.3 UNION 句

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 ステートメントを使用できる場所であれば、UNIONTABLE ステートメントまたは 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);

カラム名を強制的に同じにするには、VALUESSELECT の左側にラップし、次のようにエイリアスを使用します:

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 ALLUNION 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 結果の行の順序には必ずしも影響しません。 SELECTLIMIT がない状態で 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 以降、TABLEWHERE 句をサポートしていないことに注意して、前述の方法と同じ方法で 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 ステートメントですが、次の制限があります:

  • 最初の SELECTHIGH_PRIORITY は効果がありません。 後続の SELECTHIGH_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 UPDATELOCK IN SHARE MODE) は、UNION 以外のクエリーでのみ使用できます。 つまり、ロック句を含む SELECT ステートメントにはカッコを使用する必要があります。 このステートメントは有効ではなくなりました:

    SELECT 1 FOR UPDATE UNION SELECT 1 FOR UPDATE;

    かわりに、次のようなステートメントを記述します:

    (SELECT 1 FOR UPDATE) UNION (SELECT 1 FOR UPDATE);

関連キーワード:  ステートメント, UNION, TABLE, CREATE, ORDER, カラム, FROM, DROP, VALUES, col