为啥 LAG 除了一行之外的所有内容都返回 null?
Posted
技术标签:
【中文标题】为啥 LAG 除了一行之外的所有内容都返回 null?【英文标题】:Why does LAG return null for all but one row?为什么 LAG 除了一行之外的所有内容都返回 null? 【发布时间】:2020-03-01 07:30:00 【问题描述】:我正在尝试使用 LAG
获取组中排名第二的行以及前一个(排名第一的)行中的值。
但是,应用条件 where place = 2
会导致结果集的第一行只有 LAG
结果。
包含LEAD
列会导致预期结果显示在LAG
列中。
我使用的是 Oracle 19c,我正在使用的表如下所示:
UKNUM PARTY UKVOTES
----- ------ --------
1 con 6605
1 lab 23745
1 lib 8206
1 plaid 1859
每个uknum
至少有三行,并且所有列都不为空。
这是我的查询,旨在获取第二个放置的行(ukvotes
),并为第一个放置的行提供 ukvotes
值:
SELECT
*
FROM
(
SELECT
uknum,
rank() OVER (PARTITION BY uknum ORDER BY ukvotes DESC) AS place,
lag(ukvotes) OVER (PARTITION BY uknum ORDER BY ukvotes DESC) AS lag
FROM
ukresults
)
WHERE
place = 2
AND uknum BETWEEN 1 AND 5;
这会产生以下结果:
UKNUM PLACE LAG
---------- ---------- ----------
1 2 23745
2 2
3 2
4 2
5 2
我希望对于第 2-5 行,LAG
列中会有一个非空值。
将LEAD
添加到查询会导致LAG
列包含预期结果:
SELECT
*
FROM
(
SELECT
uknum,
rank() OVER (PARTITION BY uknum ORDER BY ukvotes DESC) AS place,
lag(ukvotes) OVER (PARTITION BY uknum ORDER BY ukvotes DESC) AS lag,
lead(ukvotes) OVER (PARTITION BY uknum ORDER BY ukvotes DESC) AS lead
FROM
ukresults
)
WHERE
place = 2
AND uknum BETWEEN 1 AND 5;
UKNUM PLACE LAG LEAD
---------- ---------- ---------- ----------
1 2 23745 6605
2 2 19262 7426
3 2 15393 10372
4 2 31288 6070
5 2 24148 11599
我很困惑为什么第一个查询没有产生预期的结果,所有行的值都是LAG
。
Here’s a DBFiddle with the data and the queries loaded.
更新:这里是来自 Oracle 19c 的查询计划,首先用于仅使用 LAG
的查询,然后是单独使用 LEAD
或 LAG
和 LEAD
一起使用的查询计划(对于包含LEAD
)。
LAG
唯一计划:
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 197 | 7683 | 5 (20)| 00:00:01 |
|* 1 | VIEW | | 197 | 7683 | 5 (20)| 00:00:01 |
|* 2 | WINDOW SORT PUSHED RANK| | 197 | 1773 | 5 (20)| 00:00:01 |
| 3 | TABLE ACCESS CLUSTER | UKRESULTS | 197 | 1773 | 4 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | UKNUMX | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("PLACE"=2)
2 - filter(RANK() OVER ( PARTITION BY "UKNUM" ORDER BY
INTERNAL_FUNCTION("UKVOTES") DESC )<=2)
4 - access("UKNUM"<=50)
仅限LEAD
/ LAG
和LEAD
计划:
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 197 | 7683 | 5 (20)| 00:00:01 |
|* 1 | VIEW | | 197 | 7683 | 5 (20)| 00:00:01 |
| 2 | WINDOW SORT | | 197 | 1773 | 5 (20)| 00:00:01 |
| 3 | TABLE ACCESS CLUSTER| UKRESULTS | 197 | 1773 | 4 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | UKNUMX | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("PLACE"=2)
4 - access("UKNUM"<=50)
【问题讨论】:
显示每一行的投票数。原始数据也会有所帮助。您可以设置某种 dbfiddle。 您的查询似乎没有产生您让我们期望的结果,但也许我没有正确的数据。 See this dbfiddle DBFiddle 可在此处获得:dbfiddle.uk/…@BobJarvis 它仅提供第一行的结果,其余为 null。 啊,非常好 - 感谢 dbfiddle。 :-) 【参考方案1】:这看起来像是优化器中的一个错误。
好像它在评估 RANK
之后,但在评估 LAG
之前将 WHERE place = 2
过滤器推送到主查询。但是,只有在第一行之后。
WHERE place = 1
会产生更奇怪的结果。
如果我在 dbfiddle 中将 Oracle 版本更改为 11g,它会产生预期的结果。
也许,这是 dbfiddble 中的错误?
【讨论】:
如果是这样,我认为这可能是Oracle本身的问题。原始结果来自我大学的 Oracle 19c 实例。 将rank()
推得更深(通过将其放在子查询中,lag
-using 子查询从中提取可以解决此问题。看来 where 子句需要与 @987654327 分开@ 由两个级别(即在此处的外部查询中)。【参考方案2】:
这很令人困惑。 lag()
真是个小伙子,因为顺序是降序的。
我的最佳猜测是uknum
s 2-5 没有第三名。
【讨论】:
lag() is really a lad
... 今日报价 :-)
每个uknum
至少有三行。以上是关于为啥 LAG 除了一行之外的所有内容都返回 null?的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 除了“/”之外的所有路由在 AWS EC2 上返回 404