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 dateparametr wejściowy. Au contraire, timestampto 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 datena timestamp with time zoneiz 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 SELECTliście:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
Słowo ASkluczowe jest wymagane w ostatnim wariancie, w dayprzeciwnym 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 SELECTliś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ą
( numericwarianty 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 timestampargumentami 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:00format ISO.
Dzięki rozdzielczości typu funkcji nadal możemy przejść date. Ale to wymaga więcej pracy od Postgres. Istnieje niejawne rzutowanie od datedo timestamporaz od datedo timestamptz. Byłoby niejednoznaczne, ale timestamptzjest „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: