使用窗口函数的SQL查询 - 插入和扩展的超前和滞后更新输出

时间:2018-01-11 12:41:20

标签: mysql sql sql-server oracle oracle-sqldeveloper

我需要一个SQL查询来使用Windowing函数Lag和Lead来执行以下操作。

对于每个Key,我需要在最终输出中执行以下Insert和update

插入条件
1.默认情况下,LAYER_NO = 0,需要写入输出 2.如果COL1,COL2,COL3的值与其宝贵记录相对应,则该记录需要写入输出。

示例:key_1 with layer_no = 2,COL3中值从400更改为600

更新条件
1.如果COL1,COL2,COL3的值与其先前记录相比没有任何变化,但“DEPART列”中有更改,则需要在输出中更新此值。

2.即使在插入带有layer_no = 0的记录后,也应按顺序更新LAYER_NO

示例:key_1 with layer_no = 3,COL1,COL2,COL3没有任何变化,但DEPART列中的值更改为“xyz”,因此需要在输出中更新。

select * from input_table;   
+-----+--------+----+----+----+------+
|  KEY|LAYER_NO|COL1|COL2|COL3|DEPART|
+-----+--------+----+----+----+------+
|key_1|       0| 200| 300| 400|   abc|->default write
|key_1|       1| 200| 300| 400|   abc|
|key_1|       2| 200| 300| 600|   abc|--->change in col3,so write
|key_1|       2| 200| 300| 600|   abc|
|key_1|       3| 200| 300| 600|   xyz|--->change in col4,so update
|key_2|       0| 500| 700| 900|   prq|->default write
|key_2|       1| 888| 555| 900|   prq|--->change in col1 & col 2,so write
|key_3|       0| 111| 222| 333|   lgh|->default write
|key_3|       1| 084| 222| 333|   lgh|--->change in col1,so write
|key_3|       2| 084| 222| 333|   rrr|--->change in col4,so update
+-----+--------+----+----+----+------+

从input_table生成以下输出的SQL查询是什么?
预期产出:

+-----+--------+----+----+----+------+
|  KEY|LAYER_NO|COl1|COl2|COl3|DEPART|
+-----+--------+----+----+----+------+
|key_1|       0| 200| 300| 400|   abc|
|key_1|       1| 200| 300| 600|   xyz|
|key_2|       0| 500| 700| 900|   prq|
|key_2|       1| 888| 555| 900|   prq|
|key_3|       0| 111| 222| 333|   lgh|
|key_3|       1| 084| 222| 333|   rrr|
+-----+--------+----+----+----+------+

1 个答案:

答案 0 :(得分:1)

这可以通过首先计算更改了col1,col2或col3列的行,然后通过查找后续行的最新离开值来完成,如下所示:

WITH your_table AS (SELECT 'key_1' KEY, 0 layer_no, 200 col1, 300 col2, 400 col3, 'abc' depart FROM dual UNION ALL
                    SELECT 'key_1' KEY, 1 layer_no, 200 col1, 300 col2, 400 col3, 'abc' depart FROM dual UNION ALL
                    SELECT 'key_1' KEY, 2 layer_no, 200 col1, 300 col2, 600 col3, 'abc' depart FROM dual UNION ALL
                    SELECT 'key_1' KEY, 2 layer_no, 200 col1, 300 col2, 600 col3, 'abc' depart FROM dual UNION ALL
                    SELECT 'key_1' KEY, 3 layer_no, 200 col1, 300 col2, 600 col3, 'xyz' depart FROM dual UNION ALL
                    SELECT 'key_2' KEY, 0 layer_no, 500 col1, 700 col2, 900 col3, 'prq' depart FROM dual UNION ALL
                    SELECT 'key_2' KEY, 1 layer_no, 888 col1, 555 col2, 900 col3, 'prq' depart FROM dual UNION ALL
                    SELECT 'key_3' KEY, 0 layer_no, 111 col1, 222 col2, 333 col3, 'lgh' depart FROM dual UNION ALL
                    SELECT 'key_3' KEY, 1 layer_no, 084 col1, 222 col2, 333 col3, 'lgh' depart FROM dual UNION ALL
                    SELECT 'key_3' KEY, 2 layer_no, 084 col1, 222 col2, 333 col3, 'rrr' depart FROM dual),
   changed_rows AS (SELECT KEY,
                           layer_no,
                           col1,
                           col2,
                           col3,
                           depart,
                           CASE WHEN LAG(col1) OVER (PARTITION BY KEY ORDER BY layer_no) = col1
                                     AND LAG(col2) OVER (PARTITION BY KEY ORDER BY layer_no) = col2
                                     AND LAG(col3) OVER (PARTITION BY KEY ORDER BY layer_no) = col3
                                     THEN 0
                                ELSE 1
                           END changed_cols1_to_3
                    FROM   your_table),
    define_grps AS (SELECT KEY,
                           layer_no,
                           col1,
                           col2,
                           col3,
                           depart,
                           changed_cols1_to_3,
                           SUM(changed_cols1_to_3) OVER (PARTITION BY KEY ORDER BY layer_no) grp
                    FROM   changed_rows)
SELECT KEY,
       grp -1 layer_no,
       col2,
       col2,
       col3,
       MAX(depart) KEEP (dense_rank LAST ORDER BY layer_no) depart
FROM   define_grps
GROUP BY KEY,
         col1,
         col2,
         col3,
         grp;

KEY     LAYER_NO       COL2       COL2       COL3 DEPART
----- ---------- ---------- ---------- ---------- ------
key_1          0        300        300        400 abc
key_1          1        300        300        600 xyz
key_2          0        700        700        900 prq
key_2          1        555        555        900 prq
key_3          1        222        222        333 rrr
key_3          0        222        222        333 lgh

changed_rows子查询检查col1,col2和col3以查看它是否具有与上一行相同的值(无更改)或不相同(更改)。我们为更改的行指定值1,为未更改的行指定0。

define_grps子查询计算出每个键的所有行的changed_cols1_to_3列的运行总计。这具有对每组连续行进行分组的效果,其中第1列,第2列和第3列是相同的。

最后,我们可以为每个组挑选最后一行。新的layer_no只是grp数减1。