Aby wygenerować serię dat, jest to optymalny sposób:
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Dodatkowe date_trunc()
nie są potrzebne. Rzutowanie do date
( day::date
) robi to niejawnie.
Ale nie ma też sensu rzutowanie literałów daty na date
parametr wejściowy. Au contraire, timestamp
to najlepszy wybór . Zaleta wydajności jest niewielka, ale nie ma powodu, aby jej nie brać. I nie trzeba niepotrzebnie stosować reguł czasu letniego (DST) w połączeniu z konwersją z date
na timestamp with time zone
iz powrotem. Zobacz poniżej.
Równoważna, mniej jednoznaczna krótka składnia:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Lub z funkcją zwracania zestawu na SELECT
liście:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
Słowo AS
kluczowe jest wymagane w ostatnim wariancie, w day
przeciwnym razie Postgres błędnie zinterpretowałby alias kolumny . I nie radziłbym tego wariantu przed Postgresem 10 - przynajmniej nie z więcej niż jedną funkcją zwracającą set na tej samej SELECT
liście:
(Pomijając to, ostatni wariant jest zwykle najszybszy z niewielkim marginesem).
Dlaczego timestamp [without time zone]
?
Istnieje wiele przeciążonych wariantów generate_series()
. Obecnie (Postgres 11):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
podpis_funkcji | typ_zwrotu
: ------------------------------------------------- ------------------------------- | : --------------------------
gene_series (liczba całkowita, liczba całkowita, liczba całkowita) | liczba całkowita
gene_series (liczba całkowita, liczba całkowita) | liczba całkowita
gene_series (bigint, bigint, bigint) | bigint
gene_series (bigint, bigint) | bigint
gene_series (numeryczne, numeryczne, numeryczne) | numeryczny
gene_series (numeryczne, numeryczne) | numeryczny
gene_series (sygnatura czasowa bez strefy czasowej, sygnatura czasowa bez strefy czasowej, interwał) | sygnatura czasowa bez strefy czasowej
gene_series (znacznik czasu ze strefą czasową, znacznik czasu ze strefą czasową, interwał) | sygnatura czasowa ze strefą czasową
( numeric
warianty zostały dodane z Postgres 9.5.) Odpowiednie są dwa ostatnie wytłuszczone i powracające timestamp
/ timestamptz
.
Nie ma wariantu przyjmowania ani zwrotudate
. Aby powrócić, potrzebne jest wyraźne rzutowanie date
. Wywołanie z timestamp
argumentami jest rozwiązywane bezpośrednio do najlepszego wariantu bez schodzenia do reguł rozpoznawania typu funkcji i bez dodatkowego rzutowania danych wejściowych.
timestamp '2004-03-07'
jest całkowicie ważny, przy okazji. Pominięta część czasu ma domyślnie 00:00
format ISO.
Dzięki rozdzielczości typu funkcji nadal możemy przejść date
. Ale to wymaga więcej pracy od Postgres. Istnieje niejawne rzutowanie od date
do timestamp
oraz od date
do timestamptz
. Byłoby niejednoznaczne, ale timestamptz
jest „preferowane” wśród „typów daty / godziny”. Tak więc mecz jest rozstrzygany w kroku 4d. :
Przeanalizuj wszystkich kandydatów i zatrzymaj te, które akceptują preferowane typy (z kategorii typu danych wejściowych) na większości stanowisk, na których wymagana będzie konwersja typów. Zachowaj wszystkich kandydatów, jeśli żaden nie akceptuje preferowanych typów. Jeśli zostanie tylko jeden kandydat, użyj go; w przeciwnym razie przejdź do następnego kroku.
Oprócz dodatkowej pracy związanej z rozwiązywaniem typów funkcji, dodaje to dodatkowe rzutowanie timestamptz
- co nie tylko zwiększa koszty, ale może również powodować problemy z czasem letnim, prowadząc w rzadkich przypadkach do nieoczekiwanych wyników. (Czas letni to kretyński pomysł, nawiasem mówiąc, nie można tego wystarczająco podkreślić).
Dodałem dema do skrzypiec pokazujące droższy plan zapytań:
db <> skrzypce tutaj
Związane z: