【sql题 累计当前行与前几行不重复的数据】

news/2024/7/9 21:45:21 标签: sql, oracle, postgresql

目录

  • 题目
  • 解题思路
  • Oracle解答
  • Postgresql解答
  • 往期题目

题目

有一张表tmp,里面有字段tjzq为字符串类型表示月份,字段num为int类型表示数量。现在需要按照tjzq进行累计求当前月与前11个与的和。
增加难度:若有重复的num。累计求和时该值只算一次。

sql">create table tmp (
     tjzq varchar(6)
    ,num int
);
insert into tmp values ('202201',1);
insert into tmp values ('202202',2);
insert into tmp values ('202203',3);
insert into tmp values ('202204',4);
insert into tmp values ('202205',5);
insert into tmp values ('202206',6);
insert into tmp values ('202207',7);
insert into tmp values ('202208',8);
insert into tmp values ('202209',9);
insert into tmp values ('202210',10);
insert into tmp values ('202211',11);
insert into tmp values ('202212',12);
insert into tmp values ('202301',13);
insert into tmp values ('202302',14);
insert into tmp values ('202303',14);
insert into tmp values ('202304',13);
insert into tmp values ('202305',12);
insert into tmp values ('202306',11);
insert into tmp values ('202307',10);
insert into tmp values ('202308',12);
insert into tmp values ('202309',15);
insert into tmp values ('202310',14);
commit;
  • 输入
    在这里插入图片描述
  • 输出
    在这里插入图片描述

解题思路

  1. 先生成所有周期,比如
    202310 对应 202310 202211
    202309 对应 202309 202210

  2. 将生成的周期跟原表进行笛卡尔积,筛选出在周期范围内的数据

  3. 根据周期进行去重聚合

Oracle解答

  • 递归方式
sql">with tmp_a as (
	select 
	     min(to_date(tjzq||'01','yyyymmdd')) tjzq_min  --最小的日期
	    ,max(to_date(tjzq||'01','yyyymmdd')) tjzq_max  --最大的日期
	from tmp
), tmp_b (start_month) as (
    select 
        tjzq_max
    from tmp_a 
    union all
    select add_months(start_month,-1) from tmp_b, tmp_a
    where to_char(add_months(start_month,-1),'yyyymm') >= to_char(tjzq_min,'yyyymm')
), tmp_c as (
   select start_month,add_months(start_month,-11) end_date from tmp_b
)
select 
     to_char(b.start_month,'yyyymm') tjzq
    ,c.num
    ,sum(distinct a.num) num_z
from tmp a, tmp_c b, tmp c
where to_date(a.tjzq||'01','yyyymmdd') >= b.end_date 
    and to_date(a.tjzq||'01','yyyymmdd') <= b.start_month
    and to_char(b.start_month,'yyyymm') = c.tjzq
group by to_char(b.start_month,'yyyymm')
    ,to_char(b.end_date,'yyyymm')
    ,c.num
order by to_char(b.start_month,'yyyymm')
;
  • 非递归方式
sql">with tmp_a as (
	select 
	     to_date(tjzq||'01','yyyymmdd') tjzq_begin
	    ,case when add_months(to_date(tjzq||'01','yyyymmdd'),-11) < tjzq_min then tjzq_min else add_months(to_date(tjzq||'01','yyyymmdd'),-11) end tjzq_end
	from tmp a, (
	    select min(to_date(tjzq||'01','yyyymmdd')) tjzq_min
	    from tmp 
	) b 
)
select 
     to_char(b.tjzq_begin,'yyyymm') tjzq
    ,c.num
    ,sum(distinct a.num) num_z
from tmp a, tmp_a b, tmp c
where to_date(a.tjzq||'01','yyyymmdd') >= b.tjzq_end 
    and to_date(a.tjzq||'01','yyyymmdd') <= b.tjzq_begin
    and to_char(b.tjzq_begin,'yyyymm') = c.tjzq
group by to_char(b.tjzq_begin,'yyyymm')
    ,to_char(b.tjzq_end,'yyyymm')
    ,c.num
order by to_char(b.tjzq_begin,'yyyymm')
;

sql_108">Postgresql解答

  • 去重后的解答方式与oracle类似
sql">with tmp_a as (
	select 
	     to_date(tjzq||'01','yyyymmdd') tjzq_begin
	    ,case when to_date(tjzq||'01','yyyymmdd')-interval '11 month' < tjzq_min then tjzq_min else to_date(tjzq||'01','yyyymmdd')-interval '11 month' end tjzq_end
	from tmp a, (
	    select min(to_date(tjzq||'01','yyyymmdd')) tjzq_min
	    from tmp 
	) b 
)
select 
     to_char(b.tjzq_begin,'yyyymm') tjzq
    ,c.num
    ,sum(distinct a.num) num_z
from tmp a, tmp_a b, tmp c
where to_date(a.tjzq||'01','yyyymmdd') >= b.tjzq_end 
    and to_date(a.tjzq||'01','yyyymmdd') <= b.tjzq_begin
    and to_char(b.tjzq_begin,'yyyymm') = c.tjzq
group by to_char(b.tjzq_begin,'yyyymm')
    ,to_char(b.tjzq_end,'yyyymm')
    ,c.num
order by to_char(b.tjzq_begin,'yyyymm')
;
  • 这里使用窗口函数实现不去重累加方式
sql">--这里的求和没有去重累加
select tjzq,num,
    sum(num) over(order by tjzq rows between 11 preceding and 0 preceding)
from tmp;

--pg不支持以下方式去重,但有的数据库支持
--pg中,窗口函数中不支持使用distinct
select tjzq,num,
    sum(distinct num) over(order by tjzq rows between 11 preceding and 0 preceding)
from tmp;

往期题目

上一题:【sql题 巧用自连】

下一题:【sql题 累计当前行与前几行不重复的数据】


http://www.niftyadmin.cn/n/153865.html

相关文章

3分钟快速了解GPT-4

编者按&#xff1a;3分钟快速了解GPT-4&#xff0c;高效获取目前关于GPT-4的重点信息。话不多说&#xff0c;Enjoy!作者 | 岳扬01 GPT-4简介说到GPT-4&#xff0c;可能你不知道&#xff0c;在北京时间今天凌晨OpenAI发布之前你可能已经用过了。根据这篇Bing Blog的内容&#xf…

5.2.3 Ext JS如何实现动态改变树节点的字体颜色

Ext JS的树显示的样式如下: 、 有时候有需要修改某个或者某些节点的样式, 比如某些节点的字体加粗,或者改变某些节点的颜色。这该如何实现呢? 实现分析 在 Ext.tree.Panel 中提供了getRootNode() 方法看起来是获取根节点的, 但其实这个方法是获取根节点的数据, 也就是…

上传验证绕过

目录上传检测流程概述上传检测流程概述靶场搭建客户端检测绕过(JS检查)less01服务端黑白名单绕过dvwa_uploadless03less04less06less07less08less09less11MIME类型检测绕过less02%00及Ox00截断绕过服务端内容检查绕过突破getimagesize及exif_imagetypeless16less17安全防范上传…

阿里P8测开晒出2月工资条,看完真的狠狠扎心了…

又是一年金三银四&#xff0c;晒薪资的又多了起来&#xff0c;有服务员、工人、护士、教师还有“程序猿”。互联网成为了21世纪的一个新物种&#xff0c;不仅使工作轻松&#xff0c;收入也相当可观&#xff0c;这就引起了大量的互联网新人加入。程序员这类技术工种在大多数人眼…

行业解决方案|智慧检务:聚焦检察院工作数字化

移动互联网时代&#xff0c;检察系统在移动智慧化的发展中一直面临着诸多挑战&#xff0c;比如&#xff1a; 1、原有系统陈旧、日常办公所需的办公应用少、移动性差&#xff0c;无法适应移动化工作。以及在移动化过程中无法保证安全等等问题非常突出。 2、跨层级多对象的协同…

单调栈及部分题目

单调栈 单调栈&#xff0c;顾名思义就是栈内元素单调按照递增(递减)顺序排列的栈。 单调递增栈&#xff1a; ①在一个队列中针对每一个元素从它右边寻找第一个比它小的元素 ②在一个队列中针对每一个元素从它左边寻找第一个比它小的元素 单调递减栈&#xff1a; ①在一个队列…

详解HTTP协议

文章目录前言一、认识URLurlencode和urldecode二、http协议格式三、http的请求方法GET和POST的区别三、HTTP的状态码重定向四、HTTP常见的HeadercookiesessionConnection总结前言 虽然说应用层协议是我们程序猿自己来定的!!! 但实际上,已经有大佬们定义了一些现成的,又非常好用…

100个正则表达式的入门实例和40个组合类型正则表达式实例

100个正则表达式的入门实例和40个组合类型正则表达式实例 正则表达式详解 数字:^[0-9]*$n位的数字: ^\d{n}$至少n位的数字: ^\d{n,}$m-n位的数字: ^\d{m,n}$零和非零开头的数字:^(0 [1-9][0-9]*)$非零开头的最多带两位小数的数字: ^([1-9][0-9]*)(\[0-9][1,2})?$带1-2位小数…