Sql 如何将列名转换为多行?

Sql 如何将列名转换为多行?,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

我有一个遗留数据库,其中包含一个具有多个布尔类型列的表。例如:

表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           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;