Щоб створити серію дат це оптимальний спосіб:
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Додатковий date_trunc()
не потрібен. Акторський склад date
( day::date
) робить це неявно.
Але також немає сенсу додавати літерали дати date
як вхідний параметр. Au contraire timestamp
- найкращий вибір . Перевага у виконанні невелика, але немає причин не брати її. І вам не потрібно зайво застосовувати правила переходу на літній час (літній час) у поєднанні з перетворенням з date
на timestamp with time zone
і назад. Дивіться нижче.
Еквівалентний, менш явний короткий синтаксис:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Або з функцією повернення набору у SELECT
списку:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
AS
Ключове слово потрібно в останньому варіанті, Postgres б перекрутити псевдонім стовпчика в day
іншому випадку. І я б не радив цей варіант до Postgres 10 - принаймні, не з більш ніж однією функцією, що повертає набір в тому ж SELECT
списку:
(Окрім того, останній варіант, як правило, найшвидший із незначним відривом.)
Чому timestamp [without time zone]
?
Існує ряд перевантажених варіантів generate_series()
. В даний час (Postgres 11):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
підпис_функції | return_type
: ------------------------------------------------- ------------------------------- | : --------------------------
create_series (ціле число, ціле число, ціле число) | ціле число
create_series (ціле число, ціле число) | ціле число
create_series (bigint, bigint, bigint) | bigint
create_series (bigint, bigint) | bigint
create_series (числовий, числовий, числовий) | числовий
create_series (числові, числові) | числовий
generated_series (відмітка часу без часового поясу, відмітка часу без часового поясу, інтервал) | позначка часу без часового поясу
generated_series (позначка часу з часовим поясом, позначка часу з часовим поясом, інтервал) | позначка часу з часовим поясом
( numeric
варіанти були додані до Postgres 9.5.) Відповідними є два останні жирним шрифтом взяття та повернення timestamp
/ timestamptz
.
Немає варіанту взяти або повернутиdate
. Для повернення потрібен явний акторський склад date
. Виклик з timestamp
аргументами переходить до найкращого варіанту безпосередньо, не опускаючись до правил роздільної здатності типу функції та без додаткового приведення для введення.
timestamp '2004-03-07'
цілком дійсний, до речі. Пропущена частина часу за замовчуванням 00:00
має формат ISO.
Завдяки роздільній здатності типу функції ми все ще можемо пройти date
. Але для цього потрібна додаткова робота Postgres. Існує неявний привід від date
до timestamp
, а також один від date
до timestamptz
. Було б неоднозначно, але timestamptz
є "кращим" серед "типів дати / часу". Тож матч вирішується на кроці 4г. :
Пройдіть усіх кандидатів і залиште тих, хто приймає бажані типи (категорії типів вхідних типів даних), на більшості позицій, де потрібно перетворення типу. Зберігайте всіх кандидатів, якщо жоден не приймає бажані типи. Якщо залишився лише один кандидат, використовуйте його; в іншому випадку перейдіть до наступного кроку.
На додаток до додаткової роботи з роздільною здатністю типу функції, це додає додатковий склад timestamptz
- що не тільки збільшує вартість, але також може спричинити проблеми з переходом на літній час, що призводить до несподіваних результатів у рідкісних випадках. (Перехід на літній час - це дебільна концепція, до речі, я не можу наголосити на цьому достатньо.)
Я додав демонстрації до скрипки, що показує більш дорогий план запитів:
db <> скрипка тут
Пов’язані: