sql:需要将日期列中的空值向右移动,而不是将空值向左移动
我有一张包含客户姓名和地址的表格sql:需要将日期列中的空值向右移动,而不是将空值向左移动,sql,oracle,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
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),并将NOTNULL列调高
例如:
输出:
CUSTOMERNAME ADD1 ADD2 ADD3 ADD4
JONY No No 1 NULL
我已经尝试过将case与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;
这种方法看起来不正确,因为这将创建一个庞大且不相关的查询
有人能建议我更好的方法吗?这应该是您需要的逻辑:
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
如果您使用的是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的方法更昂贵,但这是一个值得考虑的选项,并且你总是可以对两者(以及其他人)进行评估,看看哪一个对你的数据是最好的。
看起来是一个非常糟糕的表设计。是的,但这是要求:PL/SQL块更适合于实现你想要的,我们可以,但在企业数据仓库环境中,数据量巨大且加载频繁,这并不是最好的特性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