我有包含客户名称及其地址的表格
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;
这种方法看起来不正确,因为这会产生笨重且不相关的查询。
有人可以建议我更好的方法..
答案 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的方法更昂贵,但它是一个可以考虑的选项,您可以随时评估(和其他出现的方法)以查看哪种方法最适合您的数据