如何在BigQuery表中选择最新的分区?

csh*_*in9 7 google-bigquery

我试图从日期分区的BigQuery表中的最新分区中选择数据,但查询仍然从整个表中读取数据.

我试过(据我所知,BigQuery不支持QUALIFY):

SELECT col FROM table WHERE _PARTITIONTIME = (
  SELECT pt FROM (
    SELECT pt, RANK() OVER(ORDER by pt DESC) as rnk FROM (
      SELECT _PARTITIONTIME AS pt FROM table GROUP BY 1)
    )
  )
  WHERE rnk = 1
);
Run Code Online (Sandbox Code Playgroud)

但这不起作用并读取所有行.

SELECT col from table WHERE _PARTITIONTIME = TIMESTAMP('YYYY-MM-DD')
Run Code Online (Sandbox Code Playgroud)

'YYYY-MM-DD'特定日期在哪里工作.

但是,我需要在将来运行此脚本,但表更新(和_PARTITIONTIME)是不规则的.有没有办法只从BigQuery的最新分区中提取数据?

Mik*_*ant 15

2019 年 10 月更新

脚本存储过程的支持现在处于测试阶段(截至 2019 年 10 月)

您可以提交多个用分号分隔的语句,BigQuery 现在可以运行它们

请参阅下面的示例

DECLARE max_date TIMESTAMP;
SET max_date = (
  SELECT MAX(_PARTITIONTIME) FROM project.dataset.partitioned_table`);

SELECT * FROM `project.dataset.partitioned_table`
WHERE _PARTITIONTIME = max_date;
Run Code Online (Sandbox Code Playgroud)

更新那些喜欢在不检查上下文的情况下投票的人等。

我认为,这个答案被接受是因为它解决了 OP 的主要问题,Is there a way I can pull data only from the latest partition in BigQuery?并且在评论中提到很明显 BQ 引擎仍然扫描所有行,但仅基于最近的分区返回结果。正如在问题评论中已经提到的那样 -Still something that easily to be addressed by having that logic scripted - first getting result of subquery and then use it in final query

尝试

SELECT * FROM [dataset.partitioned_table]
WHERE _PARTITIONTIME IN (
  SELECT MAX(TIMESTAMP(partition_id))
  FROM [dataset.partitioned_table$__PARTITIONS_SUMMARY__]
)  
Run Code Online (Sandbox Code Playgroud)

或者

SELECT * FROM [dataset.partitioned_table]
WHERE _PARTITIONTIME IN (
  SELECT MAX(_PARTITIONTIME) 
  FROM [dataset.partitioned_table]
)  
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这将停止查询结果缓存(可能会影响成本)。 (3认同)
  • 当您手动探索数据时,脚本编写方法非常有用,但在使用 api 客户端并将结果存储在目标表中时则不起作用。在这些情况下,您仍然必须作为两个作业运行,第一个作业的输出用作第二个作业的输入,不幸的是:“无法为脚本设置co​​nfiguration.query.destinationTable” (2认同)
  • DECLARE 的缺点是你不能在视图中使用它 (2认同)

chh*_*yal 6

我找到了这个问题的解决方法。您可以使用with语句,选择最后几个分区并过滤掉结果。我认为这是更好的方法,因为:

  1. 您不受固定分区日期的限制(例如今天 - 1 天)。它将始终采用给定范围内的最新分区。
  2. 它只会扫描最后几个分区,而不是整个表。

最后 3 个分区扫描的示例:

WITH last_three_partitions as (select *, _PARTITIONTIME as PARTITIONTIME 
    FROM dataset.partitioned_table 
    WHERE  _PARTITIONTIME > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 3 DAY))
SELECT col1, PARTITIONTIME from last_three_partitions 
WHERE PARTITIONTIME = (SELECT max(PARTITIONTIME) from last_three_partitions)
Run Code Online (Sandbox Code Playgroud)


小智 5

列出所有分区:

#standardSQL
SELECT
  _PARTITIONTIME as pt
FROM
  `[DATASET].[TABLE]`
GROUP BY 1
Run Code Online (Sandbox Code Playgroud)

然后选择最新的时间戳。

祝你好运 :)

https://cloud.google.com/bigquery/docs/querying-partitioned-tables


Pat*_*oon 5

不好意思,这个老问题被挖掘出来了,但是它出现在Google搜索中,我认为被接受的答案具有误导性。

据我从文档和正在运行的测试中得知,接受的答案不会修剪分区,因为使用子查询来确定最新的分区:

需要解析查询的多个阶段才能解析谓词的复杂查询(例如内部查询或子查询)将不会从查询中删除分区。

因此,尽管建议的答案将提供您期望的结果,但仍将查询所有分区。它不会忽略所有较旧的分区,而只会查询最新的分区。

诀窍是使用或多或少的常量进行比较,而不是使用子查询。例如,如果_PARTITIONTIME不是日常事务而是日常事务,请尝试通过获取昨天的分区来修剪分区,如下所示:

SELECT * FROM [dataset.partitioned_table]
    WHERE _PARTITIONDATE = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
Run Code Online (Sandbox Code Playgroud)

当然,这并不总是最新的数据,但就我而言,这恰好足够接近。INTERVAL 0 DAY如果您需要今天的数据,请使用此参数,而不必关心查询在一天中尚未创建分区的那部分返回0个结果。

我很高兴了解是否有更好的解决方法来获取最新的分区!