Чтобы создать серию дат это оптимальный способ:
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качестве входного параметра. Наоборот, timestampэто лучший выбор . Преимущество в производительности небольшое, но нет причин не брать его. И вам не нужно без нужды задействовать правила перехода на летнее время (DST) вместе с преобразованием из 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';
function_signature | return_type
: ------------------------------------------------- ------------------------------- | : --------------------------
generate_series (целое, целое, целое) | целое число
generate_series (целое, целое) | целое число
generate_series (bigint, bigint, bigint) | Bigint
generate_series (bigint, bigint) | Bigint
generate_series (числовой, числовой, числовой) | числовой
generate_series (числовой, числовой) | числовой
generate_series (отметка времени без часового пояса, отметка времени без часового пояса, интервал) | отметка времени без часового пояса
generate_series (временная метка с часовым поясом, временная метка с часовым поясом, интервал) | метка времени с часовым поясом
( numericварианты были добавлены в Postgres 9.5.) Соответствующие два последних выделены жирным шрифтом take и return timestamp/ timestamptz.
Нет варианта взять или вернутьdate . Для возврата необходимо явное приведение date. Вызов с timestampаргументами преобразуется в лучший вариант напрямую, без перехода в правила разрешения типов функций и без дополнительного приведения для ввода.
timestamp '2004-03-07'совершенно верно, кстати. Пропущенная часть времени по умолчанию соответствует 00:00формату ISO.
Благодаря разрешению типа функции мы все еще можем пройти date. Но это требует от Postgres дополнительной работы. Существует неявное приведение от dateдо, timestampа также от одного dateдо timestamptz. Было бы неоднозначным, но timestamptzявляется «предпочтительным» среди «типов даты / времени». Таким образом, совпадение определяется на шаге 4d. :
Просмотрите всех кандидатов и оставьте те, которые принимают предпочтительные типы (из категории типа входных данных) в большинстве позиций, где потребуется преобразование типов. Оставьте всех кандидатов, если ни один из них не принимает предпочтительные типы. Если остается только один кандидат, используйте его; иначе переходите к следующему шагу.
В дополнение к дополнительной работе по разрешению типов функций, это добавляет дополнительное приведение к timestamptz- что не только увеличивает стоимость, но также может создавать проблемы с DST, приводящие в редких случаях к неожиданным результатам. (Летнее время - дебильная концепция, кстати, не могу не подчеркнуть этого достаточно.)
Я добавил в скрипт демонстрационные ролики, показывающие более дорогой план запроса:
db <> скрипка здесь
Связанный: