Documentation Home
MySQL 5.6 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 26.8Mb
PDF (A4) - 26.9Mb
HTML Download (TGZ) - 7.1Mb
HTML Download (Zip) - 7.2Mb


13.2.9.4 UNION 構文

SELECT ...
UNION [ALL | DISTINCT] SELECT ...
[UNION [ALL | DISTINCT] SELECT ...]

UNION は、複数の SELECT ステートメントからの結果を 1 つの結果セットに結合するために使用されます。

最初の SELECT ステートメントからのカラム名が、返される結果のカラム名として使用されます。各 SELECT ステートメントの対応する位置にリストされている選択されるカラムは、データ型が同じになるようにしてください。(たとえば、最初のステートメントによって選択される最初のカラムが、ほかのステートメントによって選択される最初のカラムと型が同じになるようにしてください。)

対応する SELECT カラムのデータ型が一致しない場合、UNION の結果内のカラムの型と長さは、すべての SELECT ステートメントによって取得された値を考慮に入れて決定されます。たとえば、次の例を考えてみます。

mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+---------------+
| REPEAT('a',1) |
+---------------+
| a             |
| bbbbbbbbbb    |
+---------------+

これらの SELECT ステートメントは通常の選択ステートメントですが、次の制限があります。

  • INTO OUTFILE を使用できるのは、最後の SELECT ステートメントだけです。(ただし、UNION の結果全体がファイルに書き込まれます。)

  • HIGH_PRIORITY を、UNION の一部である SELECT ステートメントで使用することはできません。それを最初の SELECT に対して指定しても、何の効果もありません。それを以降のいずれかの SELECT ステートメントに対して指定すると、構文エラーが発生します。

UNION のデフォルトの動作では、重複した行が結果から削除されます。オプションの DISTINCT キーワードは、これも重複した行の削除を指定するため、デフォルト以外の効果は何もありません。オプションの ALL キーワードを指定すると、重複した行の削除は実行されず、その結果には、すべての SELECT ステートメントからの一致するすべての行が含まれます。

UNION ALLUNION DISTINCT を同じクエリー内で混在させることができます。混在した UNION 型は、DISTINCT 和集合がその左側にある ALL 和集合をすべてオーバーライドするように処理されます。DISTINCT 和集合は、UNION DISTINCT を使用して明示的に、あるいはそのあとに DISTINCT または ALL キーワードのない UNION を使用して暗黙的に生成できます。

個々の SELECTORDER BY または LIMIT を適用するには、この句を 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 BYLIMIT と組み合わせて使用されます。それにより、選択された行の UNION の最終結果での順序に必ずしも影響を与えるわけではないにもかかわらず、SELECT で取得するためのこれらの行のサブセットを決定するために使用されるようになります。ORDER BYSELECT 内に LIMIT なしで現れた場合、この句はいずれにしても何も効果がないため、最適化によって削除されます。

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;

括弧のないステートメントは、今示した括弧で囲まれたステートメントと同等です。

この種の ORDER BY は、テーブル名 (つまり、tbl_name.col_name という形式の名前) を含むカラム参照を使用できません。代わりに、最初の SELECT ステートメント内にカラムのエイリアスを指定し、そのエイリアスを ORDER BY 内で参照します。(あるいは、ORDER BY 内でカラムを、そのカラム位置を使用して参照します。ただし、カラム位置の使用は非推奨です。)

また、ソートされるカラムにエイリアスが指定されている場合、ORDER BY 句はそのカラム名ではなく、エイリアスを参照する必要があります。次のうちの最初のステートメントは機能しますが、2 番目は「カラム 'a' は '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 によって 1 つずつ取得された行のセットで構成されるようにするには、ソートカラムとして使用する各 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 から取得されるかを決定することもできます。追加のカラムでは、テーブル名を示す文字列などのほかの識別情報も指定できます。


User Comments
User comments in this section are, as the name implies, provided by MySQL users. The MySQL documentation team is not responsible for, nor do they endorse, any of the information provided here.
  Posted by Lalit P on December 20, 2011
There is an issue was in the way that MySQL parses executes the queries with UNION. When you do a UNION of two tables in MySQL, the MySQL engine just appends the second data-set to the first data set without matching the column names or warning if the data types of corresponding columns are not same.
Although the official documentation does talk about being data-type agnostic, it doesn’t mention about column name being in same order in all the queries.

Example:
Lets take this example of a table.
CREATE TABLE users (
id SMALLINT NULL,
first_name VARCHAR(50) NULL,
last_name VARCHAR(50) NULL,
points SMALLINT NULL,
level SMALLINT NULL
);
+------+------------+-----------+--------+-------+
| id | first_name | last_name | points | level |
+------+------------+-----------+--------+-------+
| 1 | Lalit | Patel | 5 | 50 |
| 2 | Chuck | Norris | 10 | 100 |
+------+------------+-----------+--------+-------+
2 rows in set (0.00 sec)

The following query runs without any error and it gives the result set given below. Note that it takes the column names in the order they were specified in the first query, but mixes the values up.

(SELECT id, first_name, last_name, level, points FROM users WHERE id = 1)
UNION
(SELECT id, last_name, first_name, points, level FROM users WHERE id = 2);

+------+------------+-----------+-------+--------+
| id | first_name | last_name | level | points |
+------+------------+-----------+-------+--------+
| 1 | Lalit | Patel | 50 | 5 |
| 2 | Norris | Chuck | 10 | 100 |
+------+------------+-----------+-------+--------+
2 rows in set (0.00 sec)

If you mix up the order of the column names, the resulting data you get will be incorrect or at least not what you would be expecting in your code. MySQL will return the result as long as the number of columns are same in both the queries. A bit too much forgiving.

  Posted by Goran Ambrosic on October 26, 2012
I had one more example uf usage of an union feature.
We have to split a couple of our big database tables (>2TB) between the two servers/instances.
After the split of the tables, the structure of the tables remains the same.

First I took the data (in PHP) from one instance and I've build the result as a union (string) and put it to another instance to get finally the merged results.

Here the explanational (dummy) SQL:

SELECT
DATE_FORMAT(DATE_ADD(TIMESTAMP, INTERVAL 45 MINUTE) , '%Y-%m-%d %H:00:00') AS TIMESTAMP
, ROUND(SUM(E_Z_EVU), 3) AS E_Z_EVU
FROM (
SELECT '2012-09-01 08:00:00' AS TIMESTAMP, 0.0317 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:00:00' AS TIMESTAMP, 0.0316 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:15:00' AS TIMESTAMP, 0.0321 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:15:00' AS TIMESTAMP, 0.0319 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:30:00' AS TIMESTAMP, 0.0320 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:30:00' AS TIMESTAMP, 0.0319 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:45:00' AS TIMESTAMP, 0.0323 AS E_Z_EVU
UNION
SELECT '2012-09-01 08:40:00' AS TIMESTAMP, 0.0322 AS E_Z_EVU
) A
UNION
SELECT TIMESTAMP, E_Z_EVU
FROM archive_DB.SOME_TABLE
WHERE TIMESTAMP BETWEEN '2012-08-31 09:00:00' AND '2012-09-01 08:59:59'
GROUP BY DATE_FORMAT(DATE_ADD(TIMESTAMP, INTERVAL 45 MINUTE), '%Y-%m-%d %H:00:00')
ORDER BY TIMESTAMP

and here the example output:
+---------------------+---------+
| TIMESTAMP | E_Z_EVU |
+---------------------+---------+
| 2012-08-31 09:00:00 | 0.0044 |
| 2012-08-31 09:15:00 | 0.0034 |
| 2012-08-31 10:15:00 | 0.0039 |
| 2012-08-31 11:15:00 | 0.0181 |
| 2012-08-31 12:15:00 | 0.04 |
| 2012-08-31 13:15:00 | 0.0527 |
| 2012-08-31 14:15:00 | 0.0605 |
| 2012-08-31 15:15:00 | 0.0566 |
| 2012-08-31 16:15:00 | 0.0156 |
| 2012-08-31 17:15:00 | 0.0195 |
| 2012-08-31 18:15:00 | 0.0112 |
| 2012-08-31 19:15:00 | 0.001 |
| 2012-08-31 20:15:00 | 0 |
| 2012-08-31 21:15:00 | 0 |
| 2012-08-31 22:15:00 | 0 |
| 2012-08-31 23:15:00 | 0 |
| 2012-09-01 08:00:00 | 0.256 |
+---------------------+---------+

  Posted by Ilan Hazan on November 7, 2012
By using UNION ALL one can optimize the MySQL IN() Comparison Operations Which Include the Indexed Field.
See http://www.mysqldiary.com/optimizing-the-mysql-in-comparison-operations-which-include-the-indexed-field/
  Posted by Gianluigi Zanettini on August 21, 2014
Please be aware that if you don't add parenthesis to the query at all, the LIMIT clause will apply to the query as a WHOLE.

SELECT * FROM tbl1 WHERE user_id (1,2) UNION SELECT * FROM tbl2 WHERE user_id > 1000 LIMIT 0,50 => this will extract 2 plus 48 records.

As another thest, I run the same but with LIMIT 1,50 => this extracted 1 plus 49 records.
Sign Up Login You must be logged in to post a comment.