Получение всех записей, чей день рождения сегодня в PostgreSQL - PullRequest
7 голосов
/ 20 июля 2011

У меня следующий запрос, и мне нужно реализовать почтовую программу, которую нужно отправить всем клиентам, у которых сегодня День рождения. Это происходит ежедневно. Теперь мне нужно только выбрать клиентов Birthday, используя SQL-запрос Postgres, а не фильтровать их в PHP.

Формат даты хранится в базе данных: ГГГГ-ММ-ДД, например. 1984-03-13

У меня есть следующий запрос

SELECT cd.firstname,
       cd.surname, 
       SUBSTRING(cd.birthdate,6),
       cd.email 
FROM client_contacts AS cd 
   JOIN clients AS c ON c.id = cd.client_id 
WHERE SUBSTRING(birthdate,6) = '07-20';

Есть ли лучшие способы сделать этот запрос, чем тот, который я делал выше?

Ответы [ 6 ]

10 голосов
/ 20 июля 2011

Вы можете установить условие where на:

WHERE
    DATE_PART('day', birthdate) = date_part('day', CURRENT_DATE)
AND
    DATE_PART('month', birthdate) = date_part('month', CURRENT_DATE)
5 голосов
/ 20 июля 2011

В случае необходимости функция age позволит вам обойти високосные годы:

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
0 голосов
/ 21 апреля 2018

Ответ @ Jordan правильный, но он не будет работать, если ваш формат даты строковый. Если это строка, вы должны привести ее к типу, используя функцию to_date. затем примените функцию date_part.

Если дата рождения (DOB) - 20/04/1982, тогда запрос:

SELECT * FROM public."studentData" where date_part('day',TO_DATE("DOB", 'DD/MM/YYYY'))='20' 
AND date_part('month',TO_DATE("DOB", 'DD/MM/YYYY'))='04';

или

EXTRACT(MONTH FROM TO_DATE("DOB", 'DD/MM/YYYY'))='04' AND EXTRACT(DAY FROM TO_DATE("DOB", 'DD/MM/YYYY'))='20'

Я добавляю двойные кавычки к имени таблицы ("studentData") и имени поля ("DOB"), потому что это была строка.

Кредит @ Jordan

0 голосов
/ 24 августа 2015

Лучший способ IMO - использовать to_char(birthday, 'MM-DD') in (?), когда вы просто задаете некоторый диапазон дат, сопоставленный с 'MM-DD' вместо ?.Если вам не нужно поддерживать очень большие диапазоны дат, это решение очень простое, чистое и устойчивое к ошибкам.

0 голосов
/ 20 июля 2011
WHERE date_part('month', cd.birthdate) = '07' AND date_part('day', cd.birthdate) = '20'

Вы можете узнать больше об этом здесь

0 голосов
/ 20 июля 2011

Попробуйте что-то вроде:

WHERE EXTRACT(DOY FROM TIMESTAMP cd.birthdate) = EXTRACT(DOY FROM TIMESTAMP CURRENT_TIMESTAMP)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...