2016-12-29 30 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的做法比较昂贵,但它是值得考虑的选择,你可以随时评估两者(和拿出其他人)看看哪个数据最适合你。