web-dev-qa-db-ja.com

UNIONを使用せずに、複数の列の結果を1つの列に結合できますか?

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

この操作を行うよりエレガントな方法はありますか?

6
igx

「よりエレガントな方法」が何であるか私には不明確です。

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 |共有モードでロック]] 

WHEREGROUP BYHAVINGLIMITSELECTINTOFOR UPDATELOCK IN SHARE MODE句は、FROM句で定義された行数を増やすことができます。したがって、table_referencesfooと等しいクエリには、テーブルfooより多くの行を含めることはできません。
そのため、MySQLには、テーブルをアンピボットするような「エレガントな」方法がありません。

UNIONを使用せずにそのようなアンピボットを行う方法は、結合を使用して購入することができます。 fooテーブルの各行に3つの行を作成するため、3つの行を含む補助テーブルを作成し、(クロス)fooテーブルに結合します。これで、ベーステーブルfooの各行のクエリに3つの行があります。各クエリ行には、適切なデータを入力できます。 ELT関数の代わりに、IFまたはCASEを使用できます。

SQLフィドル

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つの行を含むテーブルを作成する方法はいくつかあります。

SQLフィドル

補助テーブルの使用

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 |
10
miracle173

UNIONの使用

他の人は、UNIONを使用せずにデータを収集するために集計を試みる回答を提出しました

この場合、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を使用しない場合

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;

ママを見て、ユニオンなし!!!

8
RolandoMySQLDBA

セミソリューション:それらは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"を検討してください。

1
Rick James

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_nameher_nameother_name

0
izogfif