web-dev-qa-db-ja.com

RedshiftでのSQL関数generate_series()の使用

Redshiftで系列の生成機能を使用したいのですが、うまくいきませんでした。

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

SQL関数を引数として使用するPostgreSQL generate_series()

19
Elm

Amazon RedshiftはPostgreSQL 8.0.2に基づいているようです 。 generate_series()のタイムスタンプ引数は8.4で追加されました。

このような問題は回避され、Redshiftではmightが機能します。

_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()やintervalデータ型を直接参照しなくても、そのテーブルを使用して簡単な日付演算を行うことができます。

_select (current_date + n)
from integers
where n < 31;
_

少なくとも8.3では機能します。

今日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
13
Gabe Brown

generate_series()関数は、Redshiftでは完全にはサポートされていません。開発者ガイドの Unsupported PostgreSQL functions セクションを参照してください。

[〜#〜]更新[〜#〜]

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関数

6
DJo

私は同様のことをする必要がありましたが、7日間に5分間隔で行いました。だからここにCTEベースのハックがあります(醜いですが冗長すぎません)

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を乗算して必要な増分を生成し、アンカー日付に適用することです。

1
El Jeffe

@ 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)
0
Derek Hill