Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
sql:需要将日期列中的空值向右移动,而不是将空值向左移动_Sql_Oracle - Fatal编程技术网

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