sql:需要将日期列中的空值移到右边而不是空左边

时间:2016-12-29 09:33:00

标签: sql oracle

我有包含客户名称及其地址的表格

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;

这种方法看起来不正确,因为这会产生笨重且不相关的查询。

有人可以建议我更好的方法..

2 个答案:

答案 0 :(得分:1)

这应该是你需要的逻辑:

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 :(得分:1)

如果您使用的是11g或更高级别,则可以将列拆分为行,这些行会丢失'空值,同时跟踪其原始顺序:

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的方法更昂贵,但它是一个可以考虑的选项,您可以随时评估(和其他出现的方法)以查看哪种方法最适合您的数据