2013-06-24 18 views
12

Mi piacerebbe utilizzare la funzione genera serie in redshift, ma non ho avuto successo.Utilizzo della funzione sql generate_series() in redshift

La documentazione di redshift dice che non è supportato. Il seguente codice funziona:

select * 
from generate_series(1,10,1) 

uscite:

1 
2 
3 
... 
10 

mi piacerebbe fare lo stesso con le date. Ho provato un certo numero di varianti, tra cui:

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

calci fuori:

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] 

cercato anche:

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

e ha cercato:

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

sia calcio out:

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] 

Se non assomiglia Userò questo codice da un altro post:

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

PostgreSQL generate_series() with SQL function as arguments

+2

Eseguire 'SELECT version()' sul database per recuperare la versione di Postgres. –

+0

Per una soluzione alternativa, vedere: http://stackoverflow.com/a/34167753/3019685 – systemjack

+0

Ho postato una soluzione alternativa a una domanda simile qui https://stackoverflow.com/questions/22759980/generate-series-method-fails- in-redshift – AlexYes

risposta

15

Amazon Redshift seems to be based on PostgreSQL 8.0.2. Gli argomenti relativi al timestamp di generate_series() sono stati aggiunti in 8.4.

Qualcosa come questo, che elude il problema, potrebbe funzionare in Redshift.

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

Funziona in PostgreSQL 8.3, che è la prima versione che posso testare. È documentato in 8.0.26.

Più tardi. . .

Sembra che sia generate_series() is unsupported in Redshift. Ma dato che hai verificato che select * from generate_series(1,10,1)fa il lavoro, la sintassi sopra ti dà almeno una possibilità di combattere. (Anche se il tipo di dati dell'intervallo è documentato come non supportato su Redshift.)

Ancora più tardi. . .

È anche possibile creare una tabella di numeri interi.

create table integers (
    n integer primary key 
); 

Compililo come preferisci. Potresti essere in grado di utilizzare generate_series() localmente, scaricare la tabella e caricarla su Redshift. (Non lo so, non uso Redshift.)

In ogni caso, è possibile eseguire semplici operazioni di aritmetica con quella tabella senza fare riferimento direttamente a generate_series() o ai tipi di dati di intervallo.

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

Funzionante in 8.3, almeno.

+3

+1 Questo sembra spiegarlo. Meno che impressionante da Amazon ... –

7

Oggi con Redshift è possibile generare un intervallo di date utilizzando le funzioni datetime e inserendo una tabella numerica.

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

genera questo per me

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 
+2

mentre questo genera una serie, non ho trovato alcun modo (CTE, sottoquery o inserimento in una tabella o tabella temporanea per unirlo ad un'altra tabella per il filtraggio). – cfeduke

+1

@cfeduke si può racchiudere questo in una tabella temporanea come '' 'con serie AS ( selezionare * da generate_series (1,10,1) ) selezionare * da serie''' – blotto

+1

@blotto - grazie! Il tuo commento e l'ultimo esempio nella domanda hanno risolto il problema per me. – GeekyDeaks

0

avevo bisogno di fare qualcosa di simile, ma con 5 minuti intervalli di più di 7 giorni. Quindi, ecco un hack basato CTE (brutto ma non troppo prolisso)

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 

dovrebbero essere in grado di estendere questo per altri schemi di generazione. Il trucco qui sta usando il join di prodotto cartesiano (cioè nessuna clausola JOIN/WHERE) per moltiplicare le CTE fatte a mano per produrre gli incrementi necessari e applicare a una data di ancoraggio.

Problemi correlati