SQL Lag distinct - 与前一个不同的值

问题描述

我通过多列表简化了以下内容。

 Person     Period           Cost_Center Previous_Cost_Center
----------- ---------------- ----------- ----------------------
123         2019003          1            
123         2019004          1            
123         2019005          2            
123         2019006          2            
123         2019007          3            

对于每个人,我想找到他以前的成本中心并将其保存在相应的列中。以前的成本中心必须与当前的不同。

我想得到什么:

Person      Period           Cost_Center Previous_Cost_Center
----------- ---------------- ----------- ---------------------
123         2019003          1           NULL 
123         2019004          1           NULL 
123         2019005          2           1 
123         2019006          2           1                     <----- Problematic row 
123         2019007          3           2 

在此期间的标准 LAG() 函数实际上会输出:

Person      Period           Cost_Center Previous_Cost_Center
----------- ---------------- ----------- ---------------------
123         2019003          1           NULL 
123         2019004          1           NULL 
123         2019005          2           1 
123         2019006          2           2                     <----- Problematic row 
123         2019007          3           2 

在有问题的行中,我想要的是最后一个不同的 Cost_Center 值,即 1 而不是 2。 我想到使用的是检查之前的Cost_Center是否不同:

          CASE
                WHEN
                    LAG ( Cost_Center ) OVER ( PARTITION BY Person ORDER BY Period ) != Cost_Center
                THEN
                    LAG ( Cost_Center ) OVER ( PARTITION BY Person ORDER BY Period )
                ELSE
                    Previous_Cost_Center
                END
            AS Previous_Cost_Center,

但是我最终在第 4 行中完全没有 Previous_Cost_Center 值。 如何使用 SQL 将其存档?如何接管最后一个不同的 Cost_Center 值以将其保存在按期间排序的 Previous_Cost_Center 中?

解决方法

将#test 替换为您的表名。它只是选择,您可以更改它以进行更新。请对此进行测试,因为您将遇到不同的情况。

SELECT s.person,s.period,s.cost_center,CASE WHEN z.person IS NULL THEN NULL ELSE z.cc END AS Previous_Cost_Center
FROM   #test s
       LEFT JOIN (SELECT *
                  FROM   (SELECT t1.*,t2.cost_center               cc,Row_number()OVER (partition BY t2.person,t1.period ORDER BY t2.period DESC) RN
                          FROM   #test t1
                                 JOIN #test t2
                                   ON t1.person = t2.person
                                      AND t1.period > t2.period
                          WHERE  t1.cost_center <> t2.cost_center)s
                  WHERE  rn = 1
         )z
              ON s.person = z.person
                 AND s.period = z.period 
,

您可以使用窗口函数执行此操作,但由于 ignore nulls 选项不可用,因此比需要的更棘手。

首先,您要为同一组的相邻值分配一个分组。

其次,您希望在分组前一个成本中心时给出第一个值。

第三,您希望在整个团队中“传播”该价值。

select t.*,max(case when immediate_prev_cost_center <> cost_center then immediate_prev_cost_center
           end) over (partition by person,cost_center,(seqnum - seqnum_2)
                     ) as prev_cost_center
  from (select t.*,row_number() over (partition by person order by period) as seqnum,row_number() over (partition by person,cost_center order by period) as seqnum_2,lag(cost_center) over (partition by person order by period) as immediate_prev_cost_center
        from t
       ) t;

行号的差异定义了组。 max() 在整个组中传播先前的值。

Here 是一个 dbfiddle。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...