SQL 滞后于前一个不同的值

SQL Lag distinct - to the previous different value

我将以下内容简化了很多列table。

 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 替换为您的 table 姓名。它只是 select,您可以将其更改为更新。请对此进行测试,因为您将遇到不同的情况。

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 

您可以使用 window 函数执行此操作,但它比必要的更棘手,因为 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 是一个 db<>fiddle.