LAG函数是一个常用的窗口函数,作用是取当前行之后的数据,即把该列数据向上错位。使用方法如下:

LAG(col ,n ,Default)

  • col 是字段名称,指明要操作的列,必须指定该参数;

  • n 表示取当前行的后n行的col列数据,可以不指定默认为1;

  • Default 表示前n行没有数据时的默认值,可以不指定默认为NULL.

二、案例表及测试数据准备

首先创建该案例的表结构、插入测试数据。

-- project表为项目表
CREATE TABLE project(
    proj_number varchar(20)  -- 项目编号
    ,name varchar(20)        -- 项目名称
    ,start_date date         -- 项目启动日期
    ,total_cost varchar(12)  -- 项目总成本:项目未完成则置NULL
    ,dept_code varchar(20)   -- 项目负责部门编号
    ,client_id varchar(20)   -- 客户编号
    ,code varchar(20)        -- 项目编码
-- assignment表存储员工在项目的工作情况
CREATE TABLE assignment(
    assign_num varchar(20)   -- 作业编号
    ,proj_number varchar(20) -- 项目编号
    ,emp_num varchar(20)     -- 员工编号
    ,date_assigned date      -- 本月开始作业日期
    ,date_ended date         -- 本月结束作业日期
    ,hours_used varchar(10)  -- 当月工时【当月作业没有结束则存NULL】
 -- 插入测试数据
INSERT INTO project 
VALUES (7001, 'Apollo',    '2020-12-17', '$10,000.90', 1, 2001, 9001)
,(7002, 'Astro',     '2021-01-01', '$20,020.87', 2, 2001, 9001)
,(7003, 'Atlantis',  '2019-12-10', '$30,000.65', 2, 2002, 9001)
,(7004, 'Barcelona', '2018-08-17', '$10,000.12', 2, 2003, 9002)
,(7005, 'Bender',    '2021-04-14', '$9,986.14', 2, 2003, 9002)
,(7006, 'Blue Moon', '2020-08-16', NULL, 3, 2004, 9003)
,(7007, 'Bordeaux',  '2013-09-16', '$105,000.67', 3, 2005, 9003)
,(7008, 'Camelot',   '2016-02-04', '$10,00.23', 3, 2006, 9004)
,(7009, 'Cheerio',   '2008-11-02', '$38,020.77', 3, 2008, 9005)
,(7010, 'Deepmind',  '2016-08-01', NULL, 3, 2010, 9005); 
INSERT INTO assignment 
VALUES (6001, 7001, 1001, '2020-12-20', '2020-12-30',  180)
,(6002, 7002, 1002, '2021-01-10', '2021-01-28',  150)
,(6003, 7003, 1001, '2019-10-12', '2019-10-20',  80)
,(6004, 7003, 1004, '2019-12-11', '2019-12-20',  90)
,(6005, 7003, 1005, '2019-12-10', '2019-12-21',  90) 
,(6006, 7003, 1006, '2019-10-11', '2019-10-24',  90)
,(6007, 7003, 1008, '2019-12-12', '2019-12-25',  100)
,(6008, 7003, 1008, '2020-01-01', '2020-01-30',  300)
,(6009, 7003, 1008, '2020-02-01', '2020-02-28',  320)
,(6010, 7004, 1010, '2018-08-17', '2018-08-29',  120)
,(6011, 7005, 1005, '2021-04-18', '2021-04-25',  36)
,(6012, 7005, 1001, '2021-04-14', '2021-04-29',  120)
,(6013, 7006, 1007, '2020-08-16', '2020-08-29',  88)
,(6014, 7006, 1008, '2020-08-11', '2020-08-27',  100)
,(6015, 7007, 1009, '2013-09-16', '2013-09-26',  120)
,(6016, 7007, 1010, '2015-01-13', '2015-01-23',  160)
,(6017, 7008, 1009, '2016-02-04', '2016-02-28',  230)
,(6018, 7009, 1007, '2010-11-03', '2010-11-29',  108)
,(6019, 7009, 1007, '2010-12-03', '2010-12-29',  108)
,(6020, 7009, 1010, '2008-11-03', '2008-11-30',  390)
,(6021, 7009, 1008, '2017-11-03', '2017-11-30',  290)
,(6022, 7009, 1002, '2009-01-01', '2009-01-30',  390)
,(6023, 7010, 1005, '2016-01-08', '2016-01-30',  398) 
,(6024, 7010, 1005, '2021-11-08', NULL, NULL);

三、LAG函数使用示例

-- 按项目编号排序后,同时查询项目编号和下一个项目编号
select 
  proj_number -- 项目编号
  ,lag(proj_number,1) over () as nextrow_proj_number  --按项目编号排序后的下一个项目编号
from project  
order by proj_number asc;

查询结果:

proj_number  nextrow_proj_number
7001         7002
7002         7003
7003         7004
7004         7005
7005         7006
7006         7007
7007         7008
7008         7009
7009         7010
7010         NULL

四、日期连续性判断问题解决

由以上结果可以直观理解LAG函数的用户,接下来提出问题:

根据员工在项目的工作时间找出非连续进行的项目名称、项目启动时间、项目当前状态。

分析:该问题的项目名称、项目启动时间、项目状态很容易取到,关键在于识别出有中断过的项目,由此会用到assignment表的员工在项目当月的开始日期(date_assigned)和结束日期(date_ended)来判断,将会有以下几种情况:

  1. 该项目在assignment表仅有一条记录,则项目未中断进行;

  2. 该项目在assignment表有多条记录,按照该项目分配员工的开始日期(date_assigned)升序排列,每个员工当月的开始日期(date_assigned)早于或等于上个员工的结束日期(date_ended)+1天,则项目未中断进行;

  3. 该项目在assignment表有多条记录,按照该项目全部员工工作记录的开始日期(date_assigned)升序排列,每个员工当月的开始日期(date_assigned)晚于上个员工的结束日期(date_ended)+1天,则项目中断过。

根据以上分析进行编写SQL:

select
   temp_1.name
   ,min(temp_2.date_assigned) as proj_start_date
   ,min(case when temp_1.total_cost is not null then 'completed'
   else 'on-going' end) as proj_status
from (
  select
    t1.proj_number
    ,t1.name
    ,t2.date_assigned
    ,t2.date_ended
    ,t1.total_cost
    ,lag(t2.date_assigned ) over (partition by t1.proj_number order by t2.date_assigned asc) as date_assigned_1
    ,lag(t2.date_ended ) over (partition by t1.proj_number order by t2.date_assigned asc) as date_ended_1
    ,case when lag(t2.date_assigned ) over (partition by t1.proj_number order by t2.date_assigned asc) is null then 'continued'
      when lag(t2.date_ended ) over (partition by t1.proj_number order by t2.date_assigned asc) >= t2.date_assigned then 'continued'
      when lag(t2.date_ended ) over (partition by t1.proj_number order by t2.date_assigned asc) < date_add(t2.date_assigned,1) then 'discontinued' end as is_continue
  from project t1
  left join assignment t2 on t1.proj_number = t2.proj_number
) temp_1
left join assignment temp_2 on temp_2.proj_number = temp_1.proj_number
where temp_1.is_continue = 'discontinued'
group by temp_1.name;

执行以上结果,找出中断过的四个项目,结果如下:

name      proj_start_date proj_status
Atlantis  2019-10-11      completed
Bordeaux  2013-09-16      completed
Cheerio   2008-11-03      completed
Deepmind  2016-01-08      on-goin
一、累计计算窗口函数 sum(field) over(partition by field order by field asc/desc rows between … and …) avg(field) over(partition by field order by field asc/desc rows between … and …) max(field) over(partition by field order by field asc/desc rows between … and …)
create table t (qdate datetime,vcode varchar(50)); insert into t values('2013-06-01','A001'); insert into t values('2013-06-02','A001'); insert into t values('2013-06-02','B001'); insert into t values...
注意:聚合函数常与 SELECT 语句的 GROUP BY 子句一块儿使用。换句话说使用聚合函数时,一个列字段要不在group by里,要没必要须在聚合函数里面,不能单独出现,不然报错。 不支持等值连接,一般使用left join、right join 或者inner join替代。 2、分号字符 分号是sql语句的结束符号,在hive中也是,但是hive对分号的识别没有那么智能,有时需要进行转义 “;” --> “\073”sql中null代表空值,但是在Hive中,String类型的字段若是空(empt
OVER(PARTITION BY order by)函数的其它用法,可查看博文https://blog.csdn.net/qq_41712271/article/details/109224538创建表和数据 cookie1,2015-04-10 10:00:02,url2 cookie1,2015-04-10 10:00:00,url1 cookie1,2015-04-10 10:03:04,1url3 cookie1,2015-04-10 10:50:05,url6 cookie1,2015-0.
Spark SQLHive中的字符串函数包括很多常用的函数,如字符串拼接、子串截取、字符串替换、大小写转换等。这些函数可以帮助我们更方便地处理字符串类型的数据。 例如,我们可以使用concat函数将多个字符串拼接在一起: SELECT concat('hello', ' ', 'world') as result; 输出结果为: +-------------+ | result | +-------------+ | hello world | +-------------+ 另外,我们还可以使用substring函数截取字符串的子串: SELECT substring('hello world', 1, 5) as result; 输出结果为: +-------+ | result| +-------+ | hello | +-------+ 除此之外,还有很多其他的字符串函数,可以根据具体的需求进行选择和使用