Вот запрос, который в большинстве случаев дает правильный результат.
SELECT
(EXTRACT(MONTH FROM DATE '1980-08-05'),
EXTRACT(DAY FROM DATE '1980-08-05'))
IN (
SELECT EXTRACT(MONTH FROM CURRENT_DATE + s.a) AS m,
EXTRACT(DAY FROM CURRENT_DATE + s.a) AS d
FROM GENERATE_SERIES(0, 6) AS s(a)
);
(он не заботится о високосных годах правильно, но вы можете снова использовать extract
для обработки подвыбора в виде високосного года вместо текущего года.
РЕДАКТИРОВАТЬ: Работает для всех случаев, и в качестве полезного запроса, а не скалярного выбора. Я использую некоторые дополнительные подвыборы, чтобы мне не приходилось вводить одну и ту же дату или выражение дважды для месяца и дня, и, конечно, фактические данные были бы в таблице вместо выражения values
. Вы можете адаптировать это по-другому. Возможно, он еще улучшится, составив более интеллектуальный ряд для недель, содержащий високосные дни, поскольку иногда этот интервал будет содержать только 6 дней (для не високосных лет).
Я постараюсь объяснить это изнутри; Сначала я нормализую целевую дату (обычно CURRENT_DATE
, но явно указанную в этом коде) в год, который, как я знаю, является високосным, так что 29 февраля появляется среди дат. Следующим шагом является создание связи со всеми рассматриваемыми парами месяц-день; Поскольку нет простого способа сделать интервальную проверку с точки зрения дня месяца, все это происходит с помощью generate_series
,
Оттуда достаточно просто извлечь месяц и день из целевого отношения (псевдоним people
) и отфильтровать только те строки, которые есть в подвыборке.
SELECT *
FROM
(select column1 as birthdate, column2 as name
from (values
(date '1982-08-05', 'Alice'),
(date '1976-02-29', 'Bob'),
(date '1980-06-10', 'Carol'),
(date '1992-06-13', 'David')
) as birthdays) as people
WHERE
((EXTRACT(MONTH FROM people.birthdate),
EXTRACT(DAY FROM people.birthdate)) IN (
SELECT EXTRACT(MONTH FROM thedate.theday + s.a) AS m,
EXTRACT(DAY FROM thedate.theday + s.a) AS d
FROM
(SELECT date (v.column1 -
(extract (YEAR FROM v.column1)-2000) * INTERVAL '1 year'
) as theday
FROM (VALUES (date '2011-06-09')) as v) as thedate,
GENERATE_SERIES(0, 6) AS s(a)
)
)
Работа в дни, как я это делал здесь, должна работать великолепно вплоть до двухмесячного интервала (если вы хотите посмотреть так далеко), поскольку 31 декабря + два месяца и изменения должны включать високосный день , С другой стороны, почти наверняка более полезно просто работать целыми месяцами для такого запроса, и в этом случае вам действительно не нужно ничего, кроме extract(month from ...
.