Recursion 如何基于同一列中的上一行值计算行值
我有以下数据集:Recursion 如何基于同一列中的上一行值计算行值,recursion,updates,teradata,Recursion,Updates,Teradata,我有以下数据集: DATE CODE RANK PARTITION ? ABS 0 1 12/04/2014 RET 1 1 20/04/2014 RET 2 1 01/05/2014 ABS 2 1 13/05/2014 RET 2 1 01/06/2015 ABS
DATE CODE RANK PARTITION
? ABS 0 1
12/04/2014 RET 1 1
20/04/2014 RET 2 1
01/05/2014 ABS 2 1
13/05/2014 RET 2 1
01/06/2015 ABS 2 1
09/10/2015 RETk 2 1
? ABS 0 2
02/04/2015 RET 1 2
03/04/2015 RET 2 2
04/04/2015 ABS 2 2
05/04/2015 STT 3 2
06/04/2015 RETk 4 2
07/04/2015 RETk 4 2
RANK是给定列DATE、CODE和同一列的上一个值的SQL中要计算的列。它在这里初始化为0。
我想实现的逻辑如下:
If RANK-1 (previous row) IS NULL AND CODE = ABS THEN RANK = 0
If RANK-1 (previous row) IS NULL AND CODE <> ABS THEN RANK <- (RANK-1) + 1
If RANK-1 = 0 or 1 AND CODE = RET THEN RANK <- (RANK-1) + 1
If RANK-1 = 2 AND CODE = STT THEN RANK <- (RANK-1) + 1
If RANK-1 = 3 AND CODE = RETk THEN RANK <- (RANK-1) + 1
If CODE = ABS THEN RANK <- (RANK-1) (previous row)
Else 0
如果秩-1(前一行)为空且code=ABS,则秩=0
如果秩-1(前一行)为空并编码为ABS,则秩如下:
create table table1
(
datecol date,
code varchar(10),
rankcol integer
);
--insert into table1 select '2014/05/13', 'RETj', 0;
select
case
when s1.code='ABS' and s2.rankcol = 1 then 1
when s1.code='RET' and s2.rankcol = 0 then 1
when s1.code='RET' and s2.rankcol = 1 then 2
else 0
end RET_res,
s1.*, s2.*
from
(select rankcol, code, row_number() OVER (order by datecol) var1 from table1) s1,
(select rankcol, code, row_number() OVER (order by datecol) var1 from table1) s2
where s1.var1=s2.var1-1
order by s1.var1
;
对于这样的任务,您始终可以使用递归查询。但是,除非每个组的行数很低,否则性能会很差
首先,您需要一种前进到下一行的方式,因为下一行的日期无法根据当前行的日期计算,因此您必须具体化数据并添加行号:
CREATE TABLE tab(dt DATE, CODE VARCHAR(10), rnk INT, part INT);
INSERT INTO tab( NULL,'ABS' ,0 , 1);
INSERT INTO tab(DATE'2014-04-12','RET' ,1 , 1);
INSERT INTO tab(DATE'2014-04-20','RET' ,2 , 1);
INSERT INTO tab(DATE'2014-05-01','ABS' ,2 , 1);
INSERT INTO tab(DATE'2014-05-13','RET' ,2 , 1);
INSERT INTO tab(DATE'2014-06-01','ABS' ,2 , 1);
INSERT INTO tab(DATE'2014-10-09','RETk',2 , 1);
INSERT INTO tab( NULL,'ABS' ,0 , 2);
INSERT INTO tab(DATE'2015-04-02','RET' ,1 , 2);
INSERT INTO tab(DATE'2015-04-03','RET' ,2 , 2);
INSERT INTO tab(DATE'2015-04-04','ABS' ,2 , 2);
INSERT INTO tab(DATE'2015-04-05','STT' ,3 , 2);
INSERT INTO tab(DATE'2015-04-06','RETk',4 , 2);
INSERT INTO tab(DATE'2015-04-07','RETk',4 , 2);
CREATE VOLATILE TABLE vt AS
(
SELECT dt, code, part
-- used to find the next row
,ROW_NUMBER() OVER (PARTITION BY part ORDER BY dt) AS rn
FROM tab
) WITH DATA
PRIMARY INDEX(part, rn)
ON COMMIT PRESERVE ROWS
;
现在,它只是使用CASE一行接一行地应用您的逻辑:
WITH RECURSIVE cte (dt, code, rnk, part, rn) AS
(
SELECT
dt
,code
,CASE WHEN code = 'ABS' THEN 0 ELSE 1 END
,part
,rn
FROM vt
WHERE rn = 1
UNION ALL
SELECT
vt.dt
,vt.code
,CASE
WHEN cte.rnk IN (0,1) AND vt.CODE = 'RET' THEN cte.rnk + 1
WHEN cte.rnk = 2 AND vt.CODE = 'STT' THEN cte.rnk + 1
WHEN cte.rnk = 3 AND vt.CODE = 'RETk' THEN cte.rnk + 1
WHEN vt.CODE = 'ABS' THEN cte.rnk
ELSE cte.rnk
END
,vt.part
,vt.rn
FROM vt JOIN cte
ON vt.part =cte.part
AND vt.rn =cte.rn + 1
)
SELECT *
FROM cte
ORDER BY part, dt;
但我认为您的逻辑实际上不是这样的(基于前几行的确切秩值),您只是停留在程序性思维中:-)
您可能只需要使用OLAP函数就可以执行所需操作…您是否尝试过前面1到1之间的行?添加您的查询,这样我们就可以看到您迄今为止所做的尝试。介于1和1之间的行无法解决问题,因为在此阶段列名未知:即使我这样做:min(RANK)over(按ID划分,按日期排列,介于1和1之间),RANK未被识别我在考虑在SQL查询中使用一个临时变量,存储前一行的值,以便在当前行计算中使用它…这有意义吗?如何使用前一行值更新用户定义的变量?是否可以添加更多行,并详细解释您想要的结果以及原因?rankcol是基于两个参数计算的:当前代码和前一个秩:除非前一行等于1且当前代码为1,否则当前行的秩不能增加等于一个特定的代码。它更像是状态机或递归模型。我在下面又增加了几个专栏,并做了更多的解释。希望这是清楚的谢谢你的答复。但是我不明白:您引用的rankcol列等于零,并且根本不更新。我需要的是返回上一行中先前计算的rankcol值,并将其作为输入来计算当前行中的rankcol,