我有一个表,记录如下:
VERSION_ID START_DATE
Vrandom1 2018-03-22
Vrandom2 2018-03-22
当我运行SQL时:
SELECT T.VERSION_ID VERSION_ID,
START_DATE,
LEAD (START_DATE) OVER (ORDER BY START_DATE) LEAD_START_DATE
FROM TABLE T
我得到了:
VERSION_ID START_DATE LEAD_START_DATE
Vrandom1 2018-03-22 2018-03-22
Vrandom2 2018-03-22 NULL
什么是正确的SQL以获得正确的前导值?
我希望两个记录都是null作为LEAD_START_DATE,或者两个记录的LEAD_START_DATE值相同。谢谢
发布于 2018-03-29 12:17:33
你的期望是错误的。SQL中的ORDER BY
是不稳定的,这意味着当键具有相同的值时,排序是任意的。即使在同一个查询中调用ORDER BY
两次也会产生不同的结果--这就是您所看到的结果。
“正确的”版本应该是期望不同的结果,并通过引入一个新的键来使排序稳定:
SELECT T.VERSION_ID VERSION_ID, START_DATE,
LEAD(START_DATE) OVER (ORDER BY START_DATE, VERSION_ID) as LEAD_START_DATE
FROM TABLE T;
但这并不能解决你的问题。
不经意间,脑海中浮现的是尝试不同的线索,但这会让人感到困惑,因为NULL
通常表示最后一个值。相反,我会改变您的期望,并引入一个稳定的排序。
发布于 2018-03-29 12:33:41
你的期望是没有根据的。
一些分析函数,LEAD()就是其中之一,需要对行进行总排序,并且对关联的处理方式与非关联没有区别。如你所见。这种情况下的结果是不确定的。
一些(但不是全部)分析函数允许您指定一个窗口。LEAD()不需要。对于那些允许窗口的函数,您可以指定一个物理偏移量(从当前问题的角度来看,这没有什么帮助,因为它仍然需要对所有行进行总排序,而不需要对关系进行特殊处理)或逻辑偏移量,其中关系完全按照您希望的方式处理。
您可以使用的一个这样的函数是FIRST_VALUE。您需要确保窗口在当前行之后开始,但是起始偏移量不是很大,以至于它也会错过相关列中具有不同值的行。因此,例如,如果您的START_DATE列的数据类型为date
,则您知道增量为1秒或更多。所以,你可以使用类似这样的东西
.......
, FIRST_VALUE(START_DATE) OVER (ORDER BY START_DATE
RANGE BETWEEN INTERVAL '1' SECOND FOLLOWING AND UNBOUNDED FOLLOWING)
发布于 2018-03-29 12:01:07
您可以使用简单的case
表达式来检查下一个与当前START_DATE
匹配的START_DATE
SELECT VERSION_ID VERSION_ID, START_DATE,
(CASE WHEN (LEAD(START_DATE,1,START_DATE) OVER (ORDER BY VERSION_ID) <> START_DATE)
THEN LEAD(START_DATE,1,START_DATE) OVER (ORDER BY VERSION_ID)
END) LEAD_START_DATE
FROM TABLE T
https://stackoverflow.com/questions/49547642
复制相似问题