Google bigquery 为什么';t LAST_值返回最后一个值?

Google bigquery 为什么';t LAST_值返回最后一个值?,google-bigquery,Google Bigquery,我想使用如下查询查找有序分区上y的最后一个值: SELECT x, LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC) FROM table 但是LAST\u VALUE返回许多不是给定分区的y的最后一个值(在本例中为最大值)的值。为什么? (在这种情况下,MAX可以代替LAST\u VALUE来查找最大值,但是为什么LAST\u VALUE也不返回最大值?TLDR:您想要的查询是: SELECT x, LAST_VALUE(y

我想使用如下查询查找有序分区上
y
的最后一个值:

SELECT
  x,
  LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC)
FROM table
但是
LAST\u VALUE
返回许多不是给定分区的
y
的最后一个值(在本例中为最大值)的值。为什么?


(在这种情况下,
MAX
可以代替
LAST\u VALUE
来查找最大值,但是为什么
LAST\u VALUE
也不返回最大值?

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

在回答这个问题之前,这里有一些关于解析函数(又称窗口函数)的背景知识。以下所有内容都是标准SQL,不特定于BigQuery

首先,分析函数不是聚合函数。聚合函数将多个输入行折叠为一个输出行,而分析函数只为每个输入行计算一个输出行。因此,您需要确保考虑每个输入行的输出是什么

其次,分析函数在行的“窗口”上运行,该窗口是该行所属“分区”的子集。输入行的分区由
partition by
子句确定,如果希望分区是整个输入行集,则可以省略它。该窗口由
ROWS
子句提供,但如果不指定(用户通常不指定),则默认为整个分区(当未应用排序时)或分区中从第一行到当前行的一组行(当存在
ORDER by
时)。请注意,对于分区中的每个输入行,窗口可能会有所不同

现在,回到
LAST\u值
。尽管上面描述的默认窗口在许多情况下是合理的(例如,计算累计和),但它在使用
最后一个\u值时效果非常差。
LAST\u VALUE
函数返回窗口中最后一行的值,默认情况下,窗口中的最后一行是当前行

因此,要解决这个问题,需要明确指定
LAST\u VALUE
的窗口是整个分区,而不仅仅是当前行之前的行。您可以按如下方式进行操作:

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
返回1、2、3、4而不是4,因为每个输入行的窗口都会更改

现在,让我们指定一个窗口作为整个分区:

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

现在我们按预期得到了4个
最后一个值

甚至问题标题也使用了
最后一个值
-问题本身要求
最大值

我只想说以下几点:

SELECT x, MAX(y) OVER (PARTITION BY x) FROM table  
若表中并没有涉及其他字段,我只需执行简单的分组方式:

SELECT x, MAX(y) FROM table GROUP BY x 

当然,我们应该记住,最大值和最大值并不总是一回事

另一个选项是将查询顺序更改为desc

SELECT
  x,
  LAST_VALUE(y) OVER (PARTITION BY x ORDER BY y ASC)
FROM table
order by x desc

但是“您将只获得第一行的最后一个值”

我问了这个问题并回答了这个问题,因为我们经常收到客户投诉,用户认为他们在“最后一个值”中发现了一个错误,我认为将其作为常见问题解答提供会很有用。我修改了这个问题,使MAX不是一个有效的答案,并在我自己的答案中添加了一条注释。谢谢你的留言!当然,这正是我的想法。我不确定用户的问题到底是什么,因为它有点模糊,因为它的措辞是:o)@MikhailBerlyant“。我们应该记住,并不总是….”-当我附加一个链接到我认为你提到的东西时,我是不是要直截了当?谢谢你的解释。这件事困扰了我好长时间。我通过DESC变通方法找到了第一个_值,但不明白为什么最后一个_值不起作用。很高兴它很有用!:-)伟大的你的回答太完整了。非常感谢你。