首页 > 其他分享 >涉及区间的查询

涉及区间的查询

时间:2022-08-30 20:44:25浏览次数:76  
标签:SAL over ProjId 查询 涉及 区间 HireDate DeptNo select

1.找出一系列连续的值

  问题:判断哪些行表示一系列连续的项目。即某一行项目开始时间和前一行的项目结束时间是一致的。

  示例表:

  

 

 

  解决方案:利用窗函数 LEAD OVER 来查找下一行的项目开始时间,从而避免使用自链接。需要按照项目ID进行排序。

select * from (
    select 
     ProjId 项目ID,ProjStart 项目开始时间,projEnd 项目结束时间,lead(ProjStart) over(order by ProjId ) 下一行项目开始时间 from projs
) V

where 项目结束时间 = 下一行项目开始时间

  

 

 

  注意:使用窗口函数时,别忘了它们是在 From 和 Where 子句之后执行的。 

  使用自连接:

select * from (
    select 
     a.ProjId 项目ID,a.ProjStart 项目开始时间,a.projEnd 项目结束时间,b.ProjStart 下一行项目开始时间 from projs a
     join projs b on a.ProjId = b.ProjId-1
) V

 

2.找出同一个分组或分区中相邻行的差

  问题:返回每位员工的 部门编号,姓名,薪水以及与当前部门中(部门编号相同)下一位员工的薪水差。这里的下一位员工是通过获聘时间确定的。对于每个部门最后获聘的员工,将薪水差设置为 N/A。

  示例表:

  

 

   解决方案:同样使用窗函数 LEAD OVER 访问下一行数据。因为比较的同部门的薪水,所以需要使用 PARTITION BY 部门编号 进行分区。

with next_sal_table (DeptNo,EName,SAL,HireDate,Next_Sal)
as
(
    select DeptNo,EName,SAL,HireDate,lead(SAL) over(partition by DeptNo order by HireDate) as Next_Sal
    from emps
)

select DeptNo,EName,SAL,HireDate,coalesce(cast(SAL-Next_Sal as char),'N/A') from next_sal_table

  为了展示解决方案的多样性,这里使用了 CTE (公用表表达式)。这里为了将 NULL 设置为 ‘N/A’ 使用了 COALESCE 函数,返回NULL列表中的第一个非值。

 

  在使用函数 LEAD OVER 时需要考虑存在重复值的情况。如果在上述表中存在相同部门相同获聘时间的员工数据,那么上述SQL语句就不正确了。因为需要的事当前员工与不同获聘日期的下一个员工的薪水差。这里我们往上数表中插入部门编号为10 获聘日期都是 ‘2022-01-02’ 的员工数据。

  

 

 

  这种情况需要跳过相同获聘日期的数据,函数 LEAD支持传入跳过的行数。

  解决方案:先计算出相同部门相同获聘日期员工的数量以及当前数据在这个分组的序号,cnt-rn+1 便是需要跳过的行数。

select DeptNo,EName,SAL,HireDate,coalesce(cast(SAL-Next_Sal as char),'N/A') from (
    select DeptNo,EName,SAL,HireDate,
    lead(SAL,cnt-rn+1) over(partition by DeptNo order by HireDate) as Next_Sal
    from (
        select DeptNo,EName,SAL,HireDate,count(*) over(partition by DeptNo,HireDate) as cnt,row_number() over(partition by DeptNo,HireDate order by Sal) rn
        from emps
    ) a

) next_sal_table

 

3.找出连续值构成的区间的起点和终点

  问题:找出连续值构成的区间,并只返回区间的起点和终点。跟上面第一个示例不同,如果某行并非一组连续值的一部分,依然要返回它。因为其自身构成区间的起点和终点。

  解决方案:首先找出所有的区间。使用窗函数 LAG Over 判断当前行的项目开始日期是否与上一行的项目结束日期是否一致,如果一致则属于分组的一部分。如果某行的项目开始日期不与上一行一致,项目结束日期也不与下一行一直,则它自己构成一组。

    找出所有分组后,给各组编号。最后找出每组的开始日期和结束日期。

select proj_group,min(ProjStart),max(projEnd) from 
(
select *,sum(flag) over(order by ProjId) as proj_group 
from (
SELECT ProjId ,ProjStart ,projEnd ,
case when lag(projEnd) over(order by ProjId ) = ProjStart 
    then 0 else 1
    end  flag
    from projs ) a
    ) b
    group by proj_group

 

  下面分步讲解:

  1.找出各个组,并给每个组的第一行做标记

SELECT ProjId ,ProjStart ,projEnd ,
case when lag(projEnd) over(order by ProjId ) = ProjStart 
    then 0 else 1
    end  flag
    from projs

   

 

 

   2.使用滑动小记 sum(flag) over(order by ProjId) as proj_group  将每个组内各行设置为同一个标记。

  

 

   3.最后根据上面的组标记进行分组聚合,取最小开始日期为连续项目的开始日期,最大结束日期为连续项目的结束日期。

 

4.填补值区间空隙

  问题:返回10年间每一年聘请的员工数,但其中有些年份并没有聘请任何员工。

  解决方案:创建一张包含 1到10 数字的透视表,也可以通过 CTE 的递归功能动态创建。根据透视表生成一个每个年份的临时表,然后外连接根据员工表聘请年份分组统计的表。使用 coalesce 函数将没有聘请数据的值设置为0。

WITH RECURSIVE Ta10 (id)
as
(
    select 1 as id
    union all
    select id+1 from Ta10
    where id <10
)

select * from Ta10

 

select y.yr,coalesce(x.cnt,0) as cnt from (
select   min_year +rn as yr
 from (
    select (
        select min(extract(year from HireDate)) from emps) as min_year,id-1 as rn from t10 
) a ) y
left join (
    select extract(year from HireDate) as yr,count(*) as cnt from emps 
    group by extract(year from HireDate)
) x on x.yr = y.yr

 

5.生成连续的数字值

  上面已经实现了这个问题,使用 CTE (公用表表达式) 的递归功能可以解决这个问题。  

 

标签:SAL,over,ProjId,查询,涉及,区间,HireDate,DeptNo,select
From: https://www.cnblogs.com/afei-24/p/16632357.html

相关文章

  • 【转】SpringBoot ElasticSearch 各种查询汇总
    原文连接:https://www.cnblogs.com/jelly12345/p/14765477.html 一:文档对象如下@Data@AllArgsConstructor@NoArgsConstructor@Document(indexName="items",type......
  • mybatis查询参数Set遍历查询
    #sqlmapper<resultMapid="BaseResultMap"type="com.LogEntity"><resultcolumn="ID"property="ID"/><resultcolumn="content_md5"property="co......
  • MyBatis复杂映射开发之多对多查询
    多对多查询的模型用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用。多对多查询的需求:查询所有用户的同时查询出该用户对应的所有角色。@startuml!th......
  • mysql查询
    目录in和exists的区别结论原理in和exists的区别结论A.idin(B)适合子表b比主表a表数据量小的情况。A.idexists(B)则相反原理in子表驱动主表,是先查出(B)的数据,2个......
  • Sql语句查询慢(持续整理中。。。。。。)
    1.坚决不使用“*”来写查询。建索引,2.减少表之间的关联3.优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据量大的表排在前面,简化查询字段,没用的......
  • MyBatis复杂映射开发之一对一查询
    一对一查询需求用户表和订单表的关系为:一个用户可以有多个订单,一个订单只能从属于一个用户一对一查询需求:查询一个订单,同时查询出该订单所对应的用户对应的sql语句:sele......
  • ElasticSearch 精确查询统计
    ElasticSearch精确查询统计match_phrase:短语匹配,不分词GETlogback-2022-08/_search{"size":1,//显示1条记录"query":{"bool":{"must":[......
  • SQL4 - 查询结果限制返回行数 - LIMIT/WHERE用法+效率分析
    题目链接戳这里LIMIT用法LIMIT2=LIMIT0,2:取前2条数据LIMITx,y=LIMITx,OFFSETy:从第x条数据开始,返回y条记录LIMIT5,10:从第6行数据开始取,取到第15行......
  • SQL5 - 将查询后的列重新命名 - AS用法
    题目链接戳这里题解为了代码更清楚,用着重号表名需要重新命名的列SELECTdevice_idAS`user_infos_example`FROMuser_profileWHEREid<=2--或用LIMIT2......
  • SQL2 - 查询多列 - SELECT查询指定列用法
    题目链接戳这里题解语法:SELECT列名1,列名2...FROM表名SELECTdevice_id,gender,age,universityFROMuser_profile......