我有一个包含几列的表格,我想要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]]
[更新| 锁定共享模式]]
无论是WHERE,GROUP BY,HAVING,LIMIT,SELECT,INTO,FOR UPDATE也不LOCK IN SHARE MODE子句可以增加由定义的行数FROM子句。所以如果table_references等于foo查询不能包含比表更多的行foo。
所以 MySQL 没有这种“优雅”的方式来反透视表。
一种无需使用 UNION 即可完成这种逆透视的方法可以使用 join 来完成。我们想为foo表的每一行创建 3 行,因此我们创建了一个包含三行的辅助表并将其(交叉)连接到foo表中。现在,对于基表中的每一行,我们的查询中有三行foo。每个查询行都可以由适当的数据填充。相反,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);
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 的三行的表:
使用辅助表:
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
May 12, 2014:没有 UNION 的查询改进May 05, 2015:从三个相关表计算值,不使用连接或联合Feb 20, 2012: SQL 数据聚合在这种情况下,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 模式fooher_namehis_nameother_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,则需要一个带有以下内容的临时表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)
| 归档时间: |
|
| 查看次数: |
138294 次 |
| 最近记录: |