2016-09-08 15 views
2

私はブール型の複数の列を持つテーブルを含むレガシーデータベースを持っています。例えば:列名を複数行に変換するにはどうすればよいですか?

TABLE_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 

私は表1のIDと名前と真である(列の名前によって表される)の属性を取得するためのSQLクエリを記述したいと思います。

予想される出力:

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; 

をしかし、これは私に(CASE-WHENのおかげで)表1の各行のための唯一の第一マッチング属性を取得します。

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 

私は書いています。

私が望む形式でデータを取得する正しい方法は何ですか?任意の入力/ヘルプは非常に高く評価されますか?

注:

  • テーブル構造が理想的ではないが、これは、レガシーシステムであり、我々は、スキーマを変更することはできません。
  • ネストされたクエリは、あまりにも遅くない限り、okです - 上記のサンプル(私は、低速で一致する行数/列係数を理解しています)。

答えて

4

最も簡単な方法は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; 
2

あなたは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' 
1

これは非常に華麗なクエリ@Gordon postedのようなものです:VALUES式は、自身の上に立つことができるので

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; 

ただ、少し短いです。

関連する問題