2016-12-29 32 views
-1

我有一個包含客戶姓名和他們的地址SQL:需要在日期列移到空值權利,而不是空值向左

CUSTOMERNAME ADD1 ADD2 ADD3 ADD4 
JONY   NULL No  No  1 
JEMMY   1  NULL No  2 
JOOJOO   1  No  No  3 
JEREMY   NULL NULL No  1 
JOCKY   1  No  NULL 2 
Jack   1  No  No  NULL  

要求是所有空的地址左移(從表ADD1對add4)並且不帶空列。

EG:

CUSTOMERNAME ADD1 ADD2 ADD3 ADD4 
JONY   NULL No  No  1 

輸出:

CUSTOMERNAME ADD1 ADD2 ADD3 ADD4 
JONY   No  No  1  NULL 

我一直在使用的情況下試圖與NVL一起,但這種方法不完全正確。

select nvl(nvl(nvl(add1,add2),add3),add4) as add1_mod , 
case when add1 is not null then nvl(nvl(add2,add3),add4) 
else add4 end as add2_mod 
from test a; 

這種方法看起來不正確,因爲這會產生龐大且不相關的查詢。

可有人請建議我更好的辦法..

+3

看起來像一個非常糟糕的桌子設計。 –

+0

是的,但這是要求:) –

+0

一個PL/SQL塊更適合於實現你想要做的事情 – GurV

回答

1

這768,16是你需要的邏輯:

select CUSTOMERNAME, 
     coalesce(ADD1, ADD2, ADD3, ADD4) as ADD1, 
     case 
     when ADD1 is not null then coalesce (ADD2, ADD3, ADD4) 
     when ADD2 is not null then coalesce (ADD3, ADD4) 
     when ADD3 is not null then ADD4     
     end as ADD2, 
     case 
     when ADD1 is not null and ADD2 is not null then coalesce(ADD3, ADD4) 
     when ADD1 is not null OR ADD2 is not null and ADD3 is not null then ADD4 
     end as ADD3, 
     case 
     when ADD1 is not null and ADD2 is not null and ADD3 is not null then ADD4 
     end as ADD4 
from test  

這是基於怎樣CASE作品中,既有使用第一個匹配的條件

的價值
SQL> select case 
    2   when 1=1 then 1 
    3   when 2=2 then 2 
    4   end 
    5 from dual; 

CASEWHEN1=1THEN1WHEN2=2THEN2END 
------------------------------- 
           1 

和返回NULL當沒有條件匹配

SQL> select nvl(case when 1=9 then 1 end, 999) 
    2 from dual; 

NVL(CASEWHEN1=9THEN1END,999) 
---------------------------- 
         999 

結果:

CUSTOMERNAME ADD1 ADD2 ADD3 ADD4 
--------------- ----- ----- ----- ----- 
JONY   No No 1 
JEMMY   1  No 2 
JOOJOO   1  No No 3 
JEREMY   No 1 
JOCKY   1  No 2 
Jack   1  No No 
1

如果你在11g或更高,你可以UNPIVOT的列行,這「失去」的空值,同時跟蹤它們的原始順序:

select customername, addr, 
    row_number() over (partition by customername order by colnum) as rn 
from test 
unpivot (addr for colnum in (add1 as 1, add2 as 2, add3 as 3, add4 as 4)) 

CUSTOMERNAME ADDR   RN 
------------ ---- ---------- 
JEMMY  1    1 
JEMMY  No   2 
JEMMY  2    3 
JEREMY  No   1 
JEREMY  1    2 
JOCKY  1    1 
... 

,然後轉動,早:

select * 
from (
    select customername, addr, 
    row_number() over (partition by customername order by colnum) as rn 
    from test 
    unpivot (addr for colnum in (add1 as 1, add2 as 2, add3 as 3, add4 as 4)) 
) 
pivot (max(addr) as addr for (rn) in (1 as a, 2 as b, 3 as c, 4 as d)) 

演示的CTE爲您的樣本數據,和重命名樞列回原來的名字:

with test (CUSTOMERNAME, ADD1, ADD2, ADD3, ADD4) as (
    select cast('JONY' as varchar2(12)), cast(NULL as varchar2(4)), 
    cast('No' as varchar2(4)), cast('No' as varchar2(4)), cast('1' as varchar2(4)) 
    from dual 
    union all select 'JEMMY', '1', NULL, 'No', '2' from dual 
    union all select 'JOOJOO', '1', 'No', 'No', '3' from dual 
    union all select 'JEREMY', NULL, NULL, 'No', '1' from dual 
    union all select 'JOCKY', '1', 'No', NULL, '2' from dual 
    union all select 'Jack', '1', 'No', 'No', NULL from dual 
) 
select customername, a_addr as add1, b_addr as add2, c_addr as add3, d_addr as add4 
from (
    select customername, addr, 
    row_number() over (partition by customername order by colnum) as rn 
    from test 
    unpivot (addr for colnum in (add1 as 1, add2 as 2, add3 as 3, add4 as 4)) 
) 
pivot (max(addr) as addr for (rn) in (1 as a, 2 as b, 3 as c, 4 as d)) 
order by customername; 

CUSTOMERNAME ADD1 ADD2 ADD3 ADD4 
------------ ---- ---- ---- ---- 
JEMMY  1 No 2   
JEREMY  No 1    
JOCKY  1 No 2   
JONY   No No 1   
JOOJOO  1 No No 3 
Jack   1 No No  

這可能比Aleksej的做法比較昂貴,但它是值得考慮的選擇,你可以隨時評估兩者(和拿出其他人)看看哪個數據最適合你。