Sql 如何将列名转换为多行?
我有一个遗留数据库,其中包含一个具有多个布尔类型列的表。例如: 表1Sql 如何将列名转换为多行?,sql,postgresql,pivot,Sql,Postgresql,Pivot,我有一个遗留数据库,其中包含一个具有多个布尔类型列的表。例如: 表1 id name has_lights has_engine has_brakes has_tyres can_move 1 bullock_cart false false false true true 2 car true true true true true 3 tank
id name has_lights has_engine has_brakes has_tyres can_move
1 bullock_cart false false false true true
2 car true true true true true
3 tank true true true false true
我想为Table1编写一个SQL查询,以获取id和名称以及属性(由列的名称表示),这些属性都是true
预期输出:
id name attributes
-- ---- ----------
1 bullock_cart has_tyres
1 bullock_cart can_move
2 car has_lights
2 car has_engine
2 car has_brakes
2 car has_tyres
2 car can_move
3 tank has_lights
3 tank has_engine
3 tank has_brakes
3 tank can_move
我写道:
SELECT id, name,
CASE
WHEN has_lights THEN 'has_lights'
WHEN has_engine THEN 'has_engine'
WHEN has_brakes THEN 'has_brakes'
WHEN has_tyres THEN 'has_tyres'
WHEN can_move THEN 'can_move'
END
FROM TABLE1;
但这只为表1中的每一行获取第一个匹配属性(通过CASE-WHEN)
以我想要的格式检索数据的正确方法是什么?如有任何意见/帮助,将不胜感激
注:
- 表结构并不理想,但这是一个遗留系统,我们无法修改模式
- 嵌套查询只要不太慢就可以了——比如说对于上面的示例(我了解慢速查询中匹配行/列的数量)
- 最简单的方法是
union all
:
select id, name, 'has_lights' as attribute from t where has_lights union all
select id, name, 'has_engine' from t where has_engine union all
select id, name, 'has_brakes' from t where has_brakes union all
select id, name, 'has_tyres' from t where has_tyres union all
select id, name, 'can_move' from t where can_move;
如果您有一个非常大的表,那么横向联接可能更有效:
select t.id, t.name, v.attribute
from t, lateral
(select attribute
from (values (has_lights, 'has_lights'),
(has_engine, 'has_engine'),
(has_brakes, 'has_brakes'),
(has_tyres, 'has_tyres'),
(can_move, 'can_move')
) v(flag, attribute)
where flag
) v;
您可以使用
UNION ALL
:
SELECT name,'has_lights' as attributes FROM YourTable where has_lights = 'TRUE'
UNION ALL
SELECT name,'has_engine' as attributes FROM YourTable where has_engine= 'TRUE'
UNION ALL
SELECT name,'has_brakes' as attributes FROM YourTable where has_brakes = 'TRUE'
UNION ALL
SELECT name,'has_tyres' as attributes FROM YourTable where has_tyres = 'TRUE'
UNION ALL
SELECT name,'can_move' as attributes FROM YourTable where can_move = 'TRUE'
这与精彩的查询非常相似: 由于
值
表达式可以独立运行,因此只需稍微缩短一点
SELECT t.id, t.name, v.attribute
FROM table1 t
JOIN LATERAL (
VALUES (has_lights, 'has_lights')
, (has_engine, 'has_engine')
, (has_brakes, 'has_brakes')
, (has_tyres , 'has_tyres')
, (can_move , 'can_move')
) v(flag, attribute) ON v.flag;