社区网友业务需求一则---数据稠化

浏览: 2019

社区网友在群里咨询了一个问题,简化后的需求如下:

获取截取到当前时间(月 to_char(a, 'yyyymm')),所有的编码(C)的最大版本号(max B),

例如:

现在有A表 数据如下:

A为时间,B为版本号,C为编码

 ltztest.jpg 


如果是2015-12月则获取a、b、c三个编码,对应的最大版本号分别为100、100、150

如果是2016-01月则获取a、b、c、d四个编码,对应的最大版本号分别为200、200、150、100

以此类推,每个月有可能新增编码,有可能没有新增(若版本号没有变化则当月没有数据,需要取该编码的历史最大版本号

希望能够一个SQL获取截取到当前所有的月份的编码的最大版本号。

想过使用开窗函数,但结果都不对。

如果能对开窗分组后的数据中的每个开窗组,分别去做外关联应该就可以,但还没使用过这样的函数。

原本他是写一个SQL每次修改时间条件,但希望一条SQL就实现

我暂时没有想到办法,与是让他用变量替换时间字段,这样不用每次修改,少一点工作量。

最后我想了很久用游标循环实现,但还是希望了解下能否有SQL可以直接select出想要的结果,于是请教了大师们。


期望结果如下:

Clipboard Image.png


附上建表语句和数据

-- Create table
create table LTZTEST
(
  a DATE,
  b NUMBER,
  c VARCHAR2(10)
)


prompt PL/SQL Developer import file
prompt Created on 2016年3月11日 by Azzo
set feedback off
set define off
prompt Disabling triggers for LTZTEST...
alter table LTZTEST disable all triggers;
prompt Deleting LTZTEST...
delete from LTZTEST;
commit;
prompt Loading LTZTEST...
insert into LTZTEST (a, b, c)
values (to_date('02-03-2016', 'dd-mm-yyyy'), 500, 'a');
insert into LTZTEST (a, b, c)
values (to_date('29-02-2016', 'dd-mm-yyyy'), 400, 'b');
insert into LTZTEST (a, b, c)
values (to_date('11-02-2016', 'dd-mm-yyyy'), 200, 'c');
insert into LTZTEST (a, b, c)
values (to_date('12-01-2016', 'dd-mm-yyyy'), 100, 'd');
insert into LTZTEST (a, b, c)
values (to_date('01-12-2015', 'dd-mm-yyyy'), 100, 'b');
insert into LTZTEST (a, b, c)
values (to_date('02-12-2015', 'dd-mm-yyyy'), 150, 'c');
insert into LTZTEST (a, b, c)
values (to_date('29-02-2016', 'dd-mm-yyyy'), 100, 'e');
insert into LTZTEST (a, b, c)
values (to_date('11-02-2016', 'dd-mm-yyyy'), 300, 'b');
insert into LTZTEST (a, b, c)
values (to_date('12-01-2016', 'dd-mm-yyyy'), 200, 'a');
insert into LTZTEST (a, b, c)
values (to_date('01-12-2015', 'dd-mm-yyyy'), 100, 'a');
insert into LTZTEST (a, b, c)
values (to_date('02-03-2016', 'dd-mm-yyyy'), 500, 'b');
insert into LTZTEST (a, b, c)
values (to_date('29-02-2016', 'dd-mm-yyyy'), 400, 'a');
insert into LTZTEST (a, b, c)
values (to_date('11-02-2016', 'dd-mm-yyyy'), 300, 'a');
insert into LTZTEST (a, b, c)
values (to_date('12-01-2016', 'dd-mm-yyyy'), 200, 'b');
insert into LTZTEST (a, b, c)
values (to_date('01-12-2015', 'dd-mm-yyyy'), 100, 'c');
commit;
prompt 15 records loaded
prompt Enabling triggers for LTZTEST...
alter table LTZTEST enable all triggers;
set feedback on
set define on
prompt Done.


稠化数据的方式一般通过笛卡尔积或者外关联实现,这个业务的需求是分区稠化,每个月都要稠化,且是截止到当月,所以相对麻烦些。

分区关联语法如下:

SELECT XX  FROM Table LEFT JOIN Table2 PARTITION BY(X) ON Table.xx=Table2.xx


最后通过Newkid大师指点,实现SQL如下:

WITH T AS (
SELECT TRUNC(A,'MM') A,C,MAX(B) B
  FROM LTZTEST
GROUP BY TRUNC(A,'MM'),C
)
,T2 AS (
SELECT DISTINCT C FROM T
)
SELECT * FROM (
SELECT T.A
      ,T2.C
      ,NVL(T.B, LAST_VALUE(T.B IGNORE NULLS) OVER(PARTITION BY T2.C ORDER BY T.A)) B
  FROM T2 LEFT JOIN T PARTITION BY(A) ON T2.C=T.C
)
WHERE B IS NOT NULL
ORDER BY A,C
;


SQL是基础,基础不牢走不稳,深感自己放下SQL很久了,希望自己能再次慢慢捡起来,不忘初心。

感谢社区网友的一则案例点醒自己,也感谢Newkid大师的点拨。


此外附上其他没有partition关联语法的数据库的解决方法:

SELECT b1.ym, b1.c, b1.b
FROM (
SELECT to_char(a1.a,'yyyymm') AS ym
,a2.c,a2.b
,row_number() over(PARTITION BY to_char(a1.a,'yyyymm'),a2.c ORDER BY a2.b DESC) AS rn
FROM LTZTEST a1
LEFT JOIN LTZTEST a2
ON a1.a >= a2.a
) b1
WHERE b1.rn = 1
ORDER BY b1.ym,b1.c
推荐 2
本文由 老头子 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

10 个评论

非常不错
哈哈,感谢感谢
后来找到了一个很巧妙地办法,不需要使用稠化报表实现。

已经微信传给你了,又可以写了博客了。

Oracle SQL问题,找老头子!~
:)
这样好像也可以:
SELECT b1.ym, b1.c, b1.b
FROM (
SELECT to_char(a1.a,'yyyymm') ym
,a1.c
,a1.b
,row_number() over(PARTITION BY to_char(a1.a,'yyyymm'),a1.c ORDER BY a1.b DESC) AS rn
FROM LTZTEST a1
) b1
WHERE b1.rn = 1
;
不可以哦,你这样做数据没有稠化1月没有c的数据了。即便1月没c的数据,我们依旧需要让他展示出来,这是需求。
SELECT b1.ym, b1.c, b1.b
FROM (
SELECT to_char(a1.a,'yyyymm') AS ym
,a2.c,a2.b
,row_number() over(PARTITION BY to_char(a1.a,'yyyymm'),a2.c ORDER BY a2.b DESC) AS rn
FROM LTZTEST a1
LEFT JOIN LTZTEST a2
ON a1.a >= a2.a
) b1
WHERE b1.rn = 1
ORDER BY b1.ym,b1.c
不知道这样可不可以
jecy

jecy 回复 jecy

老师,表关联时,关联条件写在where里边和写在on后边有什么不一样,性能一样吗?
这个是可以的,不等值连接
left join on 和where吗?结果都不一样啊

要回复文章请先登录注册