SELECT
にしたいいくつかの列を持つテーブルがあります。
SELECT his_name , her_name, other_name FROM foo;
Bu、代わりに、結果をすべて1つの列にまとめたいと思います。例として、UNION ALL
なので
SELECT her_name AS name FROM foo
UNION ALL
SELECT his_name AS name FROM foo
UNION ALL
SELECT other_name AS name FROM foo
この操作を行うよりエレガントな方法はありますか?
「よりエレガントな方法」が何であるか私には不明確です。
Oracle 次のステートメント を使用して列を行にすることができます
select all_name from foo unpivot(all_name for col_name in( his_name、 her_name、 other_name));
これは、selectステートメントの 構文図 です。
選択 [すべて| DISTINCT | DISTINCTROW] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [、select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [ GROUP BY {col_name | expr |位置} [ASC | DESC]、... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr |位置} [ASC | DESC]、...] [LIMIT {[offset、] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [、var_name]] [FOR UPDATE |共有モードでロック]]
WHERE
、GROUP BY
、HAVING
、LIMIT
、SELECT
、INTO
、FOR UPDATE
もLOCK IN SHARE MODE
句は、FROM
句で定義された行数を増やすことができます。したがって、table_references
はfoo
と等しいクエリには、テーブルfoo
より多くの行を含めることはできません。
そのため、MySQLには、テーブルをアンピボットするような「エレガントな」方法がありません。
UNIONを使用せずにそのようなアンピボットを行う方法は、結合を使用して購入することができます。 foo
テーブルの各行に3つの行を作成するため、3つの行を含む補助テーブルを作成し、(クロス)foo
テーブルに結合します。これで、ベーステーブルfoo
の各行のクエリに3つの行があります。各クエリ行には、適切なデータを入力できます。 ELT関数の代わりに、IFまたはCASEを使用できます。
MySQL 5.6スキーマ設定:
create table foo (
his_name varchar(10),
her_name varchar(10),
other_name varchar(10));
insert into foo(his_name,her_name,other_name) values ('one','two','three');
insert into foo(his_name,her_name,other_name) values ('four','five','six');
create table aux(line int);
insert into aux(line) values(1);
insert into aux(line) values(2);
insert into aux(line) values(3);
ピボットクエリ:
select elt(aux.line,foo.his_name,foo.her_name,foo.other_name) all_name
from foo cross join aux
結果:
| all_name |
|----------|
| one |
| four |
| two |
| five |
| three |
| six |
もちろん、値が1、2、3の3つの行を含むテーブルを作成する方法はいくつかあります。
補助テーブルの使用:
create table aux(line int);
insert into aux(line) values(1);
insert into aux(line) values(2);
insert into aux(line) values(3);
補助テーブルの使用:
select line
from aux
定数式を使用:
select 1 line
union all
select 2
union all
select 3
行数を数える:見つけた here
SELECT
@rownum := @rownum + 1 line
FROM
(SELECT @rownum := 0) r, INFORMATION_SCHEMA.COLUMNS t
where @rownum<3
辞書ビューの1つを使用:
SELECT
ordinal_position line
from INFORMATION_SCHEMA.COLUMNS t
where table_catalog='def'
and table_schema='information_schema'
and table_name='COLUMNS'
and ordinal_position between 1 and 3
結果:
| ORDINAL_POSITION |
|------------------|
| 1 |
| 2 |
| 3 |
他の人は、UNION
を使用せずにデータを収集するために集計を試みる回答を提出しました
May 12, 2014
: NIONを使用しないクエリの改善May 05, 2015
: 結合またはユニオンを使用せずに、3つの関連するテーブルから値を計算しますFeb 20, 2012
: SQLデータ集計この場合、UNION
を絶対に必要なのは、3つの列を1つの列にマージすることです。 UNION
を使用するよりもエレガントなものはありません
SELECT her_name AS name FROM foo
UNION
SELECT his_name AS name FROM foo
UNION
SELECT other_name AS name FROM foo;
これにより、明確な名前のリストが生成されます。
一部の列を選択し、個別の値の単一列リストを生成することが目的の場合、そのようなクエリを生成するには動的SQLが必要です。この例では、次のように仮定します
mydb
スキーマfoo
というテーブルher_name
his_name
other_name
これは、同じクエリを生成するダイナミックSQLです
USE mydb
SET group_concat_max_len = 1048576;
SELECT GROUP_CONCAT(
CONCAT('SELECT ',column_name,' AS name FROM ',table_name)
SEPARATOR ' UNION ')
INTO @sql
FROM information_schema.tables
WHERE table_schema=DATABASE() AND table_name='foo' AND column_name IN
('her_name','his_name','other_name');
SELECT @sql\G
PREPARE s FROM @sql;
EXECUTE s;
DEALLOCATE PREPEARE s;
SELECT @sql\G
では、生成されたSQLを確認できます
ストアドプロシージャを正式にスクリプト化しなくても、これで十分です。
UNION
を厳密に使用しないことを目標とする場合は、PRIMARY KEY
を含む一時テーブルが必要です。
CREATE TABLE names SELECT her_name name FROM foo WHERE 1=2;
ALTER TABLE names ADD PRIMARY KEY (name);
INSERT IGNORE INTO names (name) SELECT her_name FROM foo;
INSERT IGNORE INTO names (name) SELECT his_name FROM foo;
INSERT IGNORE INTO names (name) SELECT other_name FROM foo;
SELECT * FROM names;
DROP TABLE names;
セミソリューション:それらはcolumnになります。 (しかし、それらも1行に並んでいます。)
SELECT CONCAT_WS("\n", her_name, his_name, other_name) AS name FROM foo
例えば:
mysql> SELECT CONCAT_WS("\n", province) FROM Provinces;
+---------------------------+
| CONCAT_WS("\n", province) |
+---------------------------+
| Alberta |
| British Columbia |
| Manitoba |
| New Brunswick |
| Newfoundland and Labrador |
| Nova Scotia |
...
Webページに移動する場合は、"<br>"
ではなく"\n"
を検討してください。
MariaDBユーザーの場合:整数のシーケンスを含む仮想シーケンステーブルがあります。それらの整数で一時/補助テーブルを作成する必要はありません!
そのようなテーブルでクロス結合(デカルト積)し、ELT
を使用してn番目の列を抽出します!
ソリューション:
SELECT ELT(seq_1_to_3.seq, foo.his_name, foo.her_name, foo.other_name) AS name
FROM foo
CROSS JOIN seq_1_to_3;
説明:
仮想テーブルseq_1_to_3
には1列seq
があり、その列に1、2、3の3つの整数が含まれています。このクエリでは、テーブルfoo
の各行を3回処理します(クロス仮想テーブルと結合するseq_1_to_3
)と指定された列のリストからseq
番目の列のみを選択します:his_name
、her_name
、other_name
。