Redshift - generate_series 解决方法?

Posted

技术标签:

【中文标题】Redshift - generate_series 解决方法?【英文标题】:Redshift - generate_series workaround? 【发布时间】:2021-06-12 16:57:59 【问题描述】:

我有一个这样的机器安装表:

installationID, machineID, installed_at, uninstalled_at
A, 1, 2020-01-01, Null
B, 2, 2020-01-01, 2020-01-02
C, 3, 2020-01-02, Null
D, 2, 2020-01-04, Null

我需要一个查询来返回每天安装的机器数量。像这样:

Date, installed
2020-01-01, 2
2020-01-02, 3
2020-01-03, 2 
2020-01-04, 3

我知道给定一个日期,比如“2020-01-03”,我可以得到安装机器的数量,如下所示:

SELECT date, count(machineID) 
from installs 
where installed_at >= '2020-01-03' 
and (uninstalled_at is Null or uninstalled_at <= '2020-01-03')

另外,我知道如何在 PostgreSQL 中解决这个问题:

select generate_series dt, count(*) n
from  generate_series('2020-01-01'::timestamp , '2020-01-15'::timestamp, '1 day')  
left join tbl on installed_at <= generate_series and ( uninstalled_at is null or uninstalled_at > generate_series)
group by generate_series
order by generate_series;

(见https://***.com/a/67950775/1494511)

但是,当我在 Redshift 中尝试此操作时,我首先需要将 generate_series 更改为以下内容:

WITH TS as (
  SELECT '2021-06-01'::date - (n || ' days')::interval generate_series from generate_series (1, 5) n
) 
select generate_series dt, count(*) n
from  TS
left join tbl on installed_at <= generate_series and ( uninstalled_at is null or uninstalled_at > generate_series)
group by generate_series
order by generate_series;

注意 generate_series('2020-01-01'::timestamp , '2020-01-15'::timestamp, '1 day') 变成 SELECT '2021-06-01'::date - (n || ' days')::interval generate_series from generate_series (1, 5) n,因为 Redshift 中的语法有点不同。但这不是问题。

运行上述查询后,我得到Specified types or functions (one per INFO message) not supported on Redshift tables 由于 Redshift 大规模多处理 (MPP) 的性质,这是一个错误,如下所述:

Amazon Redshift 不完全支持 generate_series() 命令。 它可以用于仅在Leader节点上运行的查询,但不能用于涉及表的查询,因为它们涉及集群节点。唯一的解决方法是创建一个包含大量值的大表并加入它以获取一系列数字。 (前面做了一些工作,但它工作正常。)

(来自:https://***.com/a/42106596/1494511)

但是这条评论并没有给我任何关于如何在 redshift 中执行这样的查询的明确指示。

【问题讨论】:

【参考方案1】:

没有好的解决方法。 . .除非使用现有表。假设您的表格有足够的行数:

with dates as (
      select '2020-01-01'::date + (row_number() over () - 1) interval '1 day' as date
      from tbl
      limit 4
     )
select d.date, count(*) as cnt
from  dates d left join
      tbl
      on installed_at <= d.date and
         (uninstalled_at is null or uninstalled_at > d.date)
group by d.date
order by d.date;

【讨论】:

以上是关于Redshift - generate_series 解决方法?的主要内容,如果未能解决你的问题,请参考以下文章

Amazon Redshift 中的 generate_series 函数

不能在 Redshift 上使用 JOIN 和 generate_series

Redshift - generate_series 解决方法?

在 Redshift 中获取缺少 id 的行

生成带有日期和小时的时间序列并在 Amazon Redshift 中创建表

如何使用 generate_series() 生成值网格