В случае, если это имеет значение, функция возраста позволит вам обойти проблему високосных лет:
where age(cd.birthdate) - (extract(year from age(cd.birthdate)) || ' years')::interval = '0'::interval
Если вам нужна производительность, вы также можете обернуть вышеприведенное с произвольной начальной точкой (например, 'epoch'::date
) в функцию и использовать для нее индекс:
create or replace function day_of_birth(date)
returns interval
as $$
select age($1, 'epoch'::date)
- (extract(year from age($1, 'epoch'::date)) || ' years')::interval;
$$ language sql immutable strict;
create index on client_contacts(day_of_birth(birthdate));
...
where day_of_birth(cd.birthdate) = day_of_birth(current_date);
(Обратите внимание, что он технически не является неизменным, поскольку даты зависят от часового пояса. Но неизменяемая часть необходима для создания индекса, и это безопасно, если вы не меняете часовой пояс повсюду. )
РЕДАКТИРОВАТЬ: я только что немного протестировал вышеизложенное, и предложение индекса на самом деле не работает для 29 февраля. 29 февраля дает day_of_birth из 1 мес 28 дней, что, хотя и правильно, необходимо добавить к 1 января, чтобы получить действительную дату рождения для текущего года.
create or replace function birthdate(date)
returns date
as $$
select (date_trunc('year', now()::date)
+ age($1, 'epoch'::date)
- (extract(year from age($1, 'epoch'::date)) || ' years')::interval
)::date;
$$ language sql stable strict;
with dates as (
select d
from unnest('{
2004-02-28,2004-02-29,2004-03-01,
2005-02-28,2005-03-01
}'::date[]) d
)
select d,
day_of_birth(d),
birthdate(d)
from dates;
d | day_of_birth | birthdate
------------+---------------+------------
2004-02-28 | 1 mon 27 days | 2011-02-28
2004-02-29 | 1 mon 28 days | 2011-03-01
2004-03-01 | 2 mons | 2011-03-01
2005-02-28 | 1 mon 27 days | 2011-02-28
2005-03-01 | 2 mons | 2011-03-01
(5 rows)
И поэтому:
where birthdate(cd.birthdate) = current_date
20.07.2011
date_part()
, а неdatepart()
иCURRENT_DATE
, а неCURRENT_DATE()
. 20.07.2011date_part('day', column)
? 15.03.2018CURRENT_DATE
является 28 февраля невисокосного года, запрос становитсяdate_part('month', birthdate) = 2 AND date_part('day', birthdate) IN (28, 29)
, чтобы также сопоставлять людей, родившихся в високосный день. 07.07.2019