一尘不染

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

mysql

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

SELECT his_name , her_name, other_name FROM foo;

Bu,我想将结果全部合并到一个列中。例如,我可以使用UNION ALLas

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

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


阅读 77

收藏
2022-10-17

共1个答案

一尘不染

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

Oracle 你可以使用下面的语句将列变成行

select all_name
from foo
unpivot (all_name for col_name in (
  his_name, 
  her_name,
  other_name));

这是select语句的语法图

SELECT
    [ALL | 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 | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {col_name | expr | position}
      [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 | LOCK IN SHARE MODE]]

WHERE, GROUP BY, HAVING, LIMIT, SELECT,INTO和子句都FOR UPDATE不能LOCK IN SHARE MODE增加子句定义的行数FROM。所以如果table_references等于foo查询不能包含比表更多的行foo
所以 MySQL 没有这种“优雅”的方式来反透视表。

一种不使用 UNION 就可以进行这种反透视的方法可以使用连接来完成。我们要为foo表的每一行创建 3 行,因此我们创建一个包含三行的辅助表并将其(交叉)连接到foo表中。现在我们的查询中有三行,用于基表中的每一行foo。每个查询行都可以由适当的数据填充。相反,ELT 函数可以使用 IF 或 CASE。

SQLfiddle

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 的表:

SQLfiddle

使用辅助表

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

计算行号:我在这里找到了

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

使用字典视图之一

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 |
2022-10-17