我可以在没有 UNION 的情况下将多列的结果合并到一个列中吗?

igx*_*igx 8 mysql union

我有一个包含几列的表格,我想要SELECT

SELECT his_name , her_name, other_name FROM foo;
Run Code Online (Sandbox Code Playgroud)

但是,我想将所有结果合并到一个列中。举个例子,我可以做到这一点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
Run Code Online (Sandbox Code Playgroud)

有没有更优雅的方法来做这个操作?

mir*_*173 12

我不清楚什么是“更优雅的方式”。

Oracle 可以使用以下语句将列变为行

选择 all_name
来自 foo
unpivot (all_name for col_name in (
  他的名字, 
  她的名字,
  其他名字));

这是select语句的语法图

选择
    [所有 | 独特 | 区别]
      [高优先级]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [来自 table_references
      [PARTITION partition_list]
    [WHERE where_condition]
    [GROUP BY {col_name | 表达式 | 位置}
      [ASC | DESC], ... [汇总]]
    [有 where_condition]
    [ORDER BY {col_name | 表达式 | 位置}
      [ASC | DESC], ...]
    [LIMIT {[offset,] row_count | row_count OFFSET 偏移量}]
    [PROCEDURE procedure_name(argument_list)]
    [进入 OUTFILE 'file_name'
        [字符集 charset_name]
        出口选项
      | INTO DUMPFILE '文件名'
      | INTO var_name [, var_name]]
    [更新| 锁定共享模式]]

无论是WHEREGROUP BYHAVINGLIMITSELECTINTOFOR UPDATE也不LOCK IN SHARE MODE子句可以增加由定义的行数FROM子句。所以如果table_references等于foo查询不能包含比表更多的行foo
所以 MySQL 没有这种“优雅”的方式来反透视表。

一种无需使用 UNION 即可完成这种逆透视的方法可以使用 join 来完成。我们想为foo表的每一行创建 3 行,因此我们创建了一个包含三行的辅助表并将其(交叉)连接到foo表中。现在,对于基表中的每一行,我们的查询中有三行foo。每个查询行都可以由适当的数据填充。相反,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);
Run Code Online (Sandbox Code Playgroud)

枢轴查询

select elt(aux.line,foo.his_name,foo.her_name,foo.other_name) all_name
from foo  cross join  aux
Run Code Online (Sandbox Code Playgroud)

结果

| all_name |
|----------|
|      one |
|     four |
|      two |
|     five |
|    three |
|      six |
Run Code Online (Sandbox Code Playgroud)

当然,有多种方法可以创建包含值为 1、2、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);
Run Code Online (Sandbox Code Playgroud)

使用辅助表

select line
from aux
Run Code Online (Sandbox Code Playgroud)

使用常量表达式

select 1 line 
union all 
select 2 
union all 
select 3
Run Code Online (Sandbox Code Playgroud)

计算行号:我在这里找到

SELECT
 @rownum := @rownum + 1 line
 FROM
(SELECT @rownum := 0) r, INFORMATION_SCHEMA.COLUMNS t
where @rownum<3
Run Code Online (Sandbox Code Playgroud)

使用字典视图之一

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
Run Code Online (Sandbox Code Playgroud)

结果

| ORDINAL_POSITION |
|------------------|
|                1 |
|                2 |
|                3 |
Run Code Online (Sandbox Code Playgroud)


Rol*_*DBA 11

使用联合

其他人提交了答案,尝试聚合以收集数据而不使用 UNION

在这种情况下,UNION绝对必须的是将三列合并为一列。没有比使用更优雅的了UNION

SELECT her_name AS name FROM foo
UNION
SELECT his_name AS name FROM foo
UNION
SELECT other_name AS name FROM foo;
Run Code Online (Sandbox Code Playgroud)

这将产生一个不同的名称列表。

如果目的是选择一些列并生成不同值的单列列表,则需要动态 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;
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

看妈妈,没有工会!!!