2013-07-26 51 views
1

假設我有一個這樣的2x5表。轉置並比較oracle中的列值

105 blue green black red 
106 red  green white red 

我要轉這個表,並從兩列的值進行比較並顯示,如果他們在第三column.Like這

105  106 notsame 
blue red notsame 
green green same 
black white notsame 
red  red same 

我嘗試過同樣取得這個使用了大量的「工會」。但是,我如何以更小的複雜性和代碼大小來做到這一點?

+1

你是說你的表永遠不會超過2行嗎? – OldProgrammer

+0

那就對了。即使列數可能變化,我也不會超過兩行。 – user2524274

回答

1

您需要將列變爲行,這意味着您需要將它們取消轉換。我定義爲一個表工作:

create table t42(id number, colour1 varchar2(5), colour2 varchar2(5), 
    colour3 varchar2(5), colour4 varchar2(5)); 

有了您的兩行數據,您可以在UNPIVOT至10行,每行每列一個:

select * 
from (
    select id, to_char(id) as cid, colour1, colour2, colour3, colour4 
    from t42 
) 
unpivot (val for col in (cid, colour1, colour2, colour3, colour4)); 

     ID COL  VAL          
---------- ------- ---------------------------------------- 
     105 CID  105          
     105 COLOUR1 blue          
     105 COLOUR2 green          
     105 COLOUR3 black          
     105 COLOUR4 red          
     106 CID  106          
     106 COLOUR1 red          
     106 COLOUR2 green          
     106 COLOUR3 white          
     106 COLOUR4 red          

然後可以有效地重新-pivot在於:

select col, 
    max(case when rn = 1 then val end) as val1, 
    max(case when rn = 2 then val end) as val2 
from (
    select u.*, row_number() over (partition by u.col order by u.id) as rn 
    from (
    select id, to_char(id) as cid, colour1, colour2, colour3, colour4 
    from t42 
) unpivot (val for col in (cid, colour1, colour2, colour3, colour4)) u 
) 
group by col; 

COL  VAL1 VAL2 
------- ----- ----- 
CID  105 106 
COLOUR1 blue red 
COLOUR2 green green 
COLOUR3 black white 
COLOUR4 red red 

我添加了一個row_number僞列到逆透視結果,並且使用了將值分爲兩列中的一個;然後使用max摺疊空值。

然後你只需要鬆帕雷在兩列中的值:

select val1, val2, 
    case when val1 = val2 then 'same' else 'notsame' end as compare 
from (
    select col, 
    max(case when rn = 1 then val end) as val1, 
    max(case when rn = 2 then val end) as val2 
    from (
    select u.*, row_number() over (partition by u.col order by u.id) as rn 
    from (
     select id, to_char(id) as cid, colour1, colour2, colour3, colour4 
     from t42 
    ) unpivot (val for col in (cid, colour1, colour2, colour3, colour4)) u 
) 
    group by col 
); 

VAL1 VAL2 COMPARE 
----- ----- ------- 
105 106 notsame 
blue red notsame 
green green same  
black white notsame 
red red same  

如果您添加更多的列你只需要修改內逆轉置部分。

我說你有效地重新擺動,但你實際上也可以重新擺動;我想這另一條路看起來impler,persoanlly,但這可能有更好的表現和意見無論如何都會有所不同:

select a_val, b_val, 
    case when a_val = b_val then 'same' else 'notsame' end as compare 
from (
    select * from (
    select col, val, rn 
    from (
     select u.*, row_number() over (partition by u.col order by u.id) as rn 
     from (
     select id, to_char(id) as cid, colour1, colour2, colour3, colour4 
     from t42 
    ) unpivot (val for col in (cid, colour1, colour2, colour3, colour4)) u 
    ) 
) 
    pivot (max(val) as val for (rn) in (1 as a, 2 as b)) 
); 

A_VAL B_VAL COMPARE 
----- ----- ------- 
105 106 notsame 
blue red notsame 
green green same  
black white notsame 
red red same  

如果ID(或不管他們是)是固定的,你可以用這些代替rn,但我得到他們可能改變的印象。


作爲一個未經區分的變體,您可以比較不同列中的值,排序。說的數據是建立這樣的:

insert into t42 values (105, 'blue', 'green', 'black', 'red'); 
insert into t42 values (106, 'red', 'green', 'white', 'blue'); 

...所以現在兩行既有redblue,但在不同的列。你可以排名基於其名稱的值,而不是使用列名:

select val1, val2, 
    case when val1 = val2 then 'same' else 'notsame' end as compare 
from (
    select col_rnk, 
    max(case when rn = 1 then val end) as val1, 
    max(case when rn = 2 then val end) as val2 
    from (
    select u.*, 
     row_number() over (partition by u.col order by u.id) as rn, 
     rank() over (order by case when u.col = 'CID' then null else u.val end) 
     as col_rnk 
    from (
     select id, to_char(id) as cid, colour1, colour2, colour3, colour4 
     from t42 
    ) unpivot (val for col in (cid, colour1, colour2, colour3, colour4)) u 
) 
    group by col_rnk 
) 
order by val1; 

VAL1 VAL2 COMPARE 
----- ----- ------- 
105 106 notsame 
black  notsame 
blue blue same  
green green same  
red red same  
     white notsame 

我剛加入的col_rnk僞列;有一個ID列的特殊情況,但你可能不希望那樣顯示。將blackwhite或任何其他不匹配的對放入相同的結果行將需要另一個級別的操作。

+0

看起來像一個很好的解決方案。感謝所有的細節! – AngelWarrior

0

您想使用數據透視。你可以退房Oracle info on pivot in 11g

我還沒有11g的存取權,所以我無法處理一個例子。但我知道它,那就是你想要的。

下面是從連接SQL:

select * from (
    select times_purchased, state_code 
    from customers t 
) 
pivot 
(
    count(state_code) 
    for state_code in ('NY','CT','NJ','FL','MO') 
) 
order by times_purchased 

這裏是另一個SO answer which may help

或許更好,這裏有所有的PIVOT and ORACLE tagged items on SO

最後,發現another thread on Oracle's forum這可能有助於創建簡單轉。 2「有用」的答案在底部。

+0

我以前看過那篇文章。我在這個例子中遇到了一些麻煩。我想我正在尋找一些不太複雜的東西。 你能告訴我在我的例子中需要做些什麼改變嗎? – user2524274

+0

恐怕我不知道。希望有11g經驗的人會回答。 – AngelWarrior