Щоб створити серію дат це оптимальний спосіб:
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 <> скрипка тут
Пов’язані: