23

我想在redshift中使用生成系列功能,但没有成功。

红移文档说它不受支持。以下代码确实有效:

select *
from generate_series(1,10,1)

输出:

1
2
3
...
10

我想对日期做同样的事情。我尝试了许多变体,包括:

select *
from generate_series(date('2008-10-01'),date('2008-10-10 00:00:00'),1)

踢出:

 ERROR: function generate_series(date, date, integer) does not exist
 Hint: No function matches the given name and argument types.
 You may need to add explicit type casts. [SQL State=42883]

也试过:

select *
from generate_series('2008-10-01 00:00:00'::timestamp,
'2008-10-10 00:00:00'::timestamp,'1 day')

并尝试:

select *
from generate_series(cast('2008-10-01 00:00:00' as datetime),
cast('2008-10-10 00:00:00' as datetime),'1 day')

两者都踢出:

ERROR: function generate_series(timestamp without time zone, timestamp without time zone, "unknown") does not exist
Hint: No function matches the given name and argument types.
You may need to add explicit type casts. [SQL State=42883]

如果不是,我将使用另一篇文章中的此代码:

SELECT to_char(DATE '2008-01-01'
+ (interval '1 month' * generate_series(0,57)), 'YYYY-MM-DD') AS ym

PostgreSQL generate_series() 以 SQL 函数作为参数

4

7 回答 7

25

Amazon Redshift 似乎基于 PostgreSQL 8.0.2。generate_series() 的时间戳参数是在 8.4 中添加的。

像这样回避这个问题的东西可能在 Redshift 中起作用。

SELECT current_date + (n || ' days')::interval
from generate_series (1, 30) n

它适用于 PostgreSQL 8.3,这是我可以测试的最早版本。它记录在 8.0.26 中。

之后 。. .

Redshift似乎不支持 generate_series() 。但是鉴于您已经验证了它select * from generate_series(1,10,1) 确实有效,上面的语法至少给了您一个战斗的机会。(尽管间隔数据类型也被记录为在 Redshift 上不受支持。)

还是以后。. .

您还可以创建一个整数表。

create table integers (
  n integer primary key
);

随心所欲地填充它。您也许可以在本地使用 generate_series(),转储表,然后将其加载到 Redshift。(我不知道;我不使用 Redshift。)

无论如何,您可以对该表进行简单的日期运算,而无需直接引用 generate_series() 或间隔数据类型。

select (current_date + n)
from integers
where n < 31;

至少在 8.3 中有效。

于 2013-06-24T19:03:45.510 回答
20

今天使用 Redshift,您可以通过使用日期时间函数并输入数字表来生成一系列日期。

select (getdate()::date - generate_series)::date from generate_series(1,30,1)

为我生成这个

date
2015-11-06
2015-11-05
2015-11-04
2015-11-03
2015-11-02
2015-11-01
2015-10-31
2015-10-30
2015-10-29
2015-10-28
2015-10-27
2015-10-26
2015-10-25
2015-10-24
2015-10-23
2015-10-22
2015-10-21
2015-10-20
2015-10-19
2015-10-18
2015-10-17
2015-10-16
2015-10-15
2015-10-14
2015-10-13
2015-10-12
2015-10-11
2015-10-10
2015-10-09
2015-10-08
于 2015-11-07T00:51:33.607 回答
12

generate_series()Redshift 不完全支持该功能。请参阅开发人员指南中不支持的 PostgreSQL 函数部分。

更新

generate_series 现在正在使用 Redshift。

SELECT CURRENT_DATE::TIMESTAMP  - (i * interval '1 day') as date_datetime 
FROM generate_series(1,31) i 
ORDER BY 1

这将生成最近 30 天的日期

参考:Amazon Redshift 中的 generate_series 函数

于 2014-04-01T09:54:32.393 回答
2

我需要做类似的事情,但在 7 天内间隔 5 分钟。所以这是一个基于 CTE 的 hack(丑陋但不太冗长)

INSERT INTO five_min_periods
WITH 
periods  AS (select 0 as num UNION select 1 as num UNION select 2 UNION select 3 UNION select 4 UNION select 5 UNION select 6 UNION select 7 UNION select 8 UNION select 9 UNION select 10 UNION select 11),
hours    AS (select num from periods UNION ALL select num + 12 from periods),
days     AS (select num from periods where num <= 6),
rightnow AS (select CAST( TO_CHAR(GETDATE(), 'yyyy-mm-dd hh24') || ':' || trim(TO_CHAR((ROUND((DATEPART (MINUTE, GETDATE()) / 5), 1) * 5 ),'09')) AS TIMESTAMP) as start)
select  
  ROW_NUMBER() OVER(ORDER BY d.num DESC, h.num DESC, p.num DESC) as idx
  , DATEADD(minutes, -p.num * 5, DATEADD( hours, -h.num, DATEADD( days, -d.num, n.start ) ) ) AS period_date
from days d, hours h, periods p, rightnow n

应该能够将其扩展到其他生成方案。这里的技巧是使用笛卡尔积连接(即没有 JOIN/WHERE 子句)将手工制作的 CTE 相乘以产生必要的增量并应用于锚日期。

于 2017-09-06T10:33:17.810 回答
2

在撰写本文时,generate_series()在我们的 Redshift (1.0.33426) 实例上无法用于例如创建表:

# select generate_series(1,100,1);
1
2
...

# create table normal_series as select generate_series(1,100,1);
INFO: Function "generate_series(integer, integer, integer) not supported.
ERROR: Specified types or functions (one per INFO message) not supported on Redshift tables.

但是,with recursive有效:

# create table recursive_series as with recursive t(n) as (select 1::integer union all select n+1 from t where n < 100) select n from t;
SELECT

-- modify as desired, here is a date series:
# select getdate()::date + n from recursive_series;
2021-12-18
2021-12-19
...
于 2021-12-17T09:52:19.417 回答
0

Redshift 的 generate_series() 函数是仅领导节点的函数,因此您不能将其用于计算节点上的下游处理。这可以用递归 CTE 替换(或在数据库中保留“日期”表)。我在最近的回答中有一个这样的例子:

使用日期序列交叉连接 Redshift

我想在这样的答案中给出的一个警告是,在使用 Redshift 中经常发生的非常大的表时要小心不等式连接(或交叉连接或任何不合格的连接)。如果您要加入一个中等大小的 1M 行 Redshift 表,那么一切都会好起来的。但是,如果您在 1B 行的表上执行此操作,那么随着查询溢出到磁盘,数据爆炸可能会导致大量性能问题。

我已经写了几篇关于如何以对数据空间敏感的方式编写此类查询的白皮书。这种大量中间结果的问题并不是 Redshift 独有的,我首先开发了解决客户 HIVE 查询问题的方法。“为大数据编写 SQL 的第一条规则——不要做更多”

于 2021-12-17T16:43:19.557 回答
0

根据@Ryan Tuck@Slobodan Pejic 的评论,generate_series()在加入另一个表时,Redshift 不起作用。

我使用的解决方法是在查询中写出系列中的每个值:

SELECT
'2019-01-01'::date AS date_month
UNION ALL
SELECT
'2019-02-01'::date AS date_month

使用这样的 Python 函数:

import arrow

def generate_date_series(start, end):
    start = arrow.get(start)
    end = arrow.get(end)

    months = list(
        f"SELECT '{month.format('YYYY-MM-DD')}'::date AS date_month"
        for month in arrow.Arrow.range('month', start, end)
    )

    return "\nUNION ALL\n".join(months)
于 2019-09-18T15:20:52.797 回答