为什么 LAST_VALUE return 不是最后一个值?
Why doesn't LAST_VALUE return the last value?
我想使用如下查询在有序分区上找到 y
的最后一个值:
SELECT
x,
LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC)
FROM table
但是 LAST_VALUE
returns 很多值不是给定分区的 y
的最后一个值(在本例中为最大值)。为什么?
(在这种情况下,可以用MAX
代替LAST_VALUE
求最大值,但是为什么LAST_VALUE
return也不是最大值?)
TLDR:你要查询的是:
SELECT
x,
LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM table
可能后跟 GROUP BY
以折叠来自分析函数的重复输出行。
当然,如果您只需要在无序分区上使用 MAX
会更简单:
SELECT
x,
MAX(y) OVER (PARTITION BY x)
FROM table
在回答这个问题之前,先了解一下解析函数的背景知识(a.k.a。window 函数)。以下所有内容都是标准的 SQL,并非特定于 BigQuery。
首先,解析函数不是聚合函数。聚合函数将多个输入行合并为一个输出行,而分析函数为每个输入行准确计算一个输出行。因此,您需要确保考虑 每个 输入行的输出。
其次,分析函数对 "window" 行进行操作,这些行是该行所属的 "partition" 行的子集。输入行的分区由 PARTITION BY
子句确定,或者如果您希望分区是整个输入行集,则可以省略它。 window 由 ROWS
子句给出,但如果您不指定它(用户通常不指定),它默认为整个分区(未应用排序时)或分区中从第一行到当前行的行集(当存在 ORDER BY
时)。请注意,分区中每个输入行的 window 可能不同!
现在,回到 LAST_VALUE
。虽然上面描述的默认 window 在许多情况下是合理的(例如,计算累积和),但它在 LAST_VALUE
下的效果非常差。 LAST_VALUE
函数 returns 中最后一行的值 window,默认情况下 window 中的最后一行是当前行。
因此,要解决此问题,您需要明确指定 LAST_VALUE
的 window 是整个分区,而不仅仅是当前行之前的行。您可以这样做:
SELECT x, LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM table
为了对此进行测试,这里有一个例子:
SELECT
x,
FIRST_VALUE(x) OVER (ORDER BY x ASC) first_asc,
FIRST_VALUE(x) OVER (ORDER BY x DESC) first_desc,
LAST_VALUE(x) OVER (ORDER BY x ASC) last_asc,
LAST_VALUE(x) OVER (ORDER BY x DESC) last_desc,
FROM
(SELECT 4 as x),
(SELECT 2 as x),
(SELECT 1 as x),
(SELECT 3 as x)
x,first_asc,first_desc,last_asc,last_desc
1,1,4,1,1
2,1,4,2,2
3,1,4,3,3
4,1,4,4,4
请注意 LAST_VALUE
returns 1, 2, 3, 4 而不仅仅是 4,因为每个输入行的 window 都会发生变化。
现在让我们指定一个 window 即整个分区:
SELECT
x,
FIRST_VALUE(x) OVER (ORDER BY x ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) first_asc,
FIRST_VALUE(x) OVER (ORDER BY x DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) first_desc,
LAST_VALUE(x) OVER (ORDER BY x ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_asc,
LAST_VALUE(x) OVER (ORDER BY x DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_desc,
FROM
(SELECT 4 as x),
(SELECT 2 as x),
(SELECT 1 as x),
(SELECT 3 as x)
x,first_asc,first_desc,last_asc,last_desc
1,1,4,4,1
2,1,4,4,1
3,1,4,4,1
4,1,4,4,1
现在我们如预期的那样 LAST_VALUE
得到 4。
即使该问题标题也使用 LAST_VALUE
- 问题本身要求 Largest Value
!
我会选择以下内容:
SELECT x, MAX(y) OVER (PARTITION BY x) FROM table
如果不涉及 table 中的其他字段 - 我只会进行简单的 GROUP BY:
SELECT x, MAX(y) FROM table GROUP BY x
当然,我们应该记住,Largest value 和 MAX value 并不总是一回事。
您可以选择将查询顺序更改为 desc
SELECT
x,
LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC)
FROM table
order by x desc
但是您只会得到第一行的最后一个值
我想使用如下查询在有序分区上找到 y
的最后一个值:
SELECT
x,
LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC)
FROM table
但是 LAST_VALUE
returns 很多值不是给定分区的 y
的最后一个值(在本例中为最大值)。为什么?
(在这种情况下,可以用MAX
代替LAST_VALUE
求最大值,但是为什么LAST_VALUE
return也不是最大值?)
TLDR:你要查询的是:
SELECT
x,
LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM table
可能后跟 GROUP BY
以折叠来自分析函数的重复输出行。
当然,如果您只需要在无序分区上使用 MAX
会更简单:
SELECT
x,
MAX(y) OVER (PARTITION BY x)
FROM table
在回答这个问题之前,先了解一下解析函数的背景知识(a.k.a。window 函数)。以下所有内容都是标准的 SQL,并非特定于 BigQuery。
首先,解析函数不是聚合函数。聚合函数将多个输入行合并为一个输出行,而分析函数为每个输入行准确计算一个输出行。因此,您需要确保考虑 每个 输入行的输出。
其次,分析函数对 "window" 行进行操作,这些行是该行所属的 "partition" 行的子集。输入行的分区由 PARTITION BY
子句确定,或者如果您希望分区是整个输入行集,则可以省略它。 window 由 ROWS
子句给出,但如果您不指定它(用户通常不指定),它默认为整个分区(未应用排序时)或分区中从第一行到当前行的行集(当存在 ORDER BY
时)。请注意,分区中每个输入行的 window 可能不同!
现在,回到 LAST_VALUE
。虽然上面描述的默认 window 在许多情况下是合理的(例如,计算累积和),但它在 LAST_VALUE
下的效果非常差。 LAST_VALUE
函数 returns 中最后一行的值 window,默认情况下 window 中的最后一行是当前行。
因此,要解决此问题,您需要明确指定 LAST_VALUE
的 window 是整个分区,而不仅仅是当前行之前的行。您可以这样做:
SELECT x, LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM table
为了对此进行测试,这里有一个例子:
SELECT
x,
FIRST_VALUE(x) OVER (ORDER BY x ASC) first_asc,
FIRST_VALUE(x) OVER (ORDER BY x DESC) first_desc,
LAST_VALUE(x) OVER (ORDER BY x ASC) last_asc,
LAST_VALUE(x) OVER (ORDER BY x DESC) last_desc,
FROM
(SELECT 4 as x),
(SELECT 2 as x),
(SELECT 1 as x),
(SELECT 3 as x)
x,first_asc,first_desc,last_asc,last_desc
1,1,4,1,1
2,1,4,2,2
3,1,4,3,3
4,1,4,4,4
请注意 LAST_VALUE
returns 1, 2, 3, 4 而不仅仅是 4,因为每个输入行的 window 都会发生变化。
现在让我们指定一个 window 即整个分区:
SELECT
x,
FIRST_VALUE(x) OVER (ORDER BY x ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) first_asc,
FIRST_VALUE(x) OVER (ORDER BY x DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) first_desc,
LAST_VALUE(x) OVER (ORDER BY x ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_asc,
LAST_VALUE(x) OVER (ORDER BY x DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_desc,
FROM
(SELECT 4 as x),
(SELECT 2 as x),
(SELECT 1 as x),
(SELECT 3 as x)
x,first_asc,first_desc,last_asc,last_desc
1,1,4,4,1
2,1,4,4,1
3,1,4,4,1
4,1,4,4,1
现在我们如预期的那样 LAST_VALUE
得到 4。
即使该问题标题也使用 LAST_VALUE
- 问题本身要求 Largest Value
!
我会选择以下内容:
SELECT x, MAX(y) OVER (PARTITION BY x) FROM table
如果不涉及 table 中的其他字段 - 我只会进行简单的 GROUP BY:
SELECT x, MAX(y) FROM table GROUP BY x
当然,我们应该记住,Largest value 和 MAX value 并不总是一回事。
您可以选择将查询顺序更改为 desc
SELECT
x,
LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC)
FROM table
order by x desc
但是您只会得到第一行的最后一个值