Funkcja przyjmuje 2 lub 3 argumenty, które są liczbami lub datą. Trzeci argument (step) nie jest wymagany dla wartości typu biginteger (domyślnie jest równy 1), ale jest konieczny gdy chcemy stworzyć serie dla timestapów:
generate_series(start, stop, step)
Sprawdźmy kilka podstawowych przypadków:
test=# select generate_series(1,5) as d; d --- 1 2 3 4 5 (5 rows) test=# select generate_series(5,1,-1) as d; d --- 5 4 3 2 1 (5 rows) test=# select generate_series('2010-03-01'::timestamp, '2010-03-05', '24 hours'); generate_series --------------------- 2010-03-01 00:00:00 2010-03-02 00:00:00 2010-03-03 00:00:00 2010-03-04 00:00:00 2010-03-05 00:00:00 (5 rows) test=# select generate_series(1,2) as id , date(generate_series('2010-03-01'::timestamp, '2010-03-05', '24 hours')); id | date ----+------------ 1 | 2010-03-01 2 | 2010-03-02 1 | 2010-03-03 2 | 2010-03-04 1 | 2010-03-05 2 | 2010-03-01 1 | 2010-03-02 2 | 2010-03-03 1 | 2010-03-04 2 | 2010-03-05 (10 rows)Funkcja jest także bardzo pomocna przy generowaniu danych testowych. Wystarczy, że użyjemy razem z nią funkcji random:
test=# select r from (select generate_series(1,5) as id, round(random()*100) as r) as foo; r ---- 76 93 91 68 34 (5 rows)
Generowanie kolejno zdefiniowanych ciągu znaków:
test=# SELECT myarray[i] as element FROM (SELECT ARRAY['one','two','tree','four','five','six'] As myarray) as foo CROSS JOIN generate_series(1, 6) As i; element --------- one two tree four five six (6 rows)A co z tekstami? Jeśli wystarczy, że będą to ciągi znaków w pełni losowych, to możemy użyć do tego jeszcze funkcji substring i md5:
test=# select c2 from (select generate_series(1,10) as id, substring(md5(random()::text) from 0 for 20) as c2) foo; c2 --------------------- 81b7985f41be65f56cb dd516dc4e04d39b3356 b40721cfc0738bf98ed 5ca0de341103fbb87de 2e8b3a407257743261f 7e45b2df06fb93d0821 cbec578dcd1a86366fb 83fecb8953dc5b07813 6317b12d53e5da59d87 ad35dc89a0772e49684 (10 rows)
Przejdźmy jednak do konkretnego przypadku raportu, który potrzebuję wygenerować. W tabeli table1 trzymam informacje o klientach, którzy pojawili się w danym czasie (kolumna: appeared_at, typ timestamp). Ja jednak potrzebuję wiedzieć tylko ile było takich osób danego dnia. Raport wymaga aby policzyć klientów dla wszystkich dni (więc dla dni, gdzie klienci się nie pojawili potrzebuję wyświetlić 0). Dlatego potrzebuję użyć RIGHT JOINa z tabelką, która jest serią podstawowych danych o datach z wybranego przedziału i zwykłym iterowaniem (dla lepszego pokazaniu wyniku).
test=# SELECT seq.id, seq.date, concat(data.count,0) FROM ( SELECT date(appeared_at) AS date, count(*) FROM table1 WHERE appeared_at BETWEEN '2010-03-01' AND '2010-03-10' GROUP BY DATE(appeared_at) ) data RIGHT JOIN ( SELECT generate_series(1,10) as id, DATE(generate_series('2010-03-01'::timestamp, '2010-03-10', '24 hours')) AS date ) seq ON seq.date = data.date ORDER BY seq.id; id | date | concat ----+------------+-------- 1 | 2010-03-01 | 20400 2 | 2010-03-02 | 12330 3 | 2010-03-03 | 29770 4 | 2010-03-04 | 15500 5 | 2010-03-05 | 15170 6 | 2010-03-06 | 22150 7 | 2010-03-07 | 140620 8 | 2010-03-08 | 106960 9 | 2010-03-09 | 34480 10 | 2010-03-10 | 0 (10 rows)Proste, prawda? :-)
Brak komentarzy:
Prześlij komentarz