Хобрук: Ваш путь к мастерству в программировании

Получение всех записей, день рождения которых сегодня в PostgreSQL

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

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

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

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';

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

20.07.2011

Ответы:


1

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

WHERE
    DATE_PART('day', birthdate) = date_part('day', CURRENT_DATE)
AND
    DATE_PART('month', birthdate) = date_part('month', CURRENT_DATE)
20.07.2011
  • как насчет людей, которые родились в прошлом году? 20.07.2011
  • Видимо, мне нужно лечь спать, а не отвечать на вопросы на SO. Я отредактирую. 20.07.2011
  • @jordan - Спасибо за усилия, но ни одному из наших клиентов еще не исполнился 1 день ;-) 20.07.2011
  • @Jordan - кажется, у меня есть другая проблема. Я получаю синтаксическую ошибку CURRENT_DATE()), думаю, это может быть из-за старой версии Postgres, установленной на сервере, версия PostgreSQL 8.1.22. 20.07.2011
  • Это должно быть date_part(), а не datepart() и CURRENT_DATE, а не CURRENT_DATE(). 20.07.2011
  • @a_horse_with_no_name: как я уже сказал, мне нужно было просто лечь спать :) Спасибо за исправления. Я обновил свой ответ правильной формой для потомков. 20.07.2011
  • Хе-хе. Я по-прежнему думаю, что мой подход лучше подходит для людей/контрактов от 29 февраля. ;-) 20.07.2011
  • Просто любопытно, чтобы включить использование индекса для этого WHERE, вам нужно определить индекс (возможно, с двумя столбцами) с помощью date_part('day', column)? 15.03.2018
  • Я тоже пришел к этому решению, за исключением того, что когда CURRENT_DATE является 28 февраля невисокосного года, запрос становится date_part('month', birthdate) = 2 AND date_part('day', birthdate) IN (28, 29), чтобы также сопоставлять людей, родившихся в високосный день. 07.07.2019

  • 2

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

    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

    3
    WHERE date_part('month', cd.birthdate) = '07' AND date_part('day', cd.birthdate) = '20'
    

    Подробнее об этом можно прочитать здесь

    20.07.2011
  • Спасибо, но возникает эта ошибка. ПОДСКАЗКА: Ни одна функция не соответствует заданному имени и типам аргументов. Возможно, вам потребуется добавить явное приведение типов. 20.07.2011
  • datepart() не является функцией Postgres, это должно быть date_part() 20.07.2011
  • Да, я пропустил подчеркивание. Но вы должны использовать решение @Jordan, оно лучшее. 21.07.2011

  • 4

    Ответ @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';
    

    or

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

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

    Кредит @Jordan

    21.04.2018

    5

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

    WHERE EXTRACT(DOY FROM TIMESTAMP cd.birthdate) = EXTRACT(DOY FROM TIMESTAMP CURRENT_TIMESTAMP)
    
    20.07.2011
  • Я тоже об этом думал - тогда ответ Джордана - хороший :) 20.07.2011
  • Нет, это не так... Он извлекает год вместо дня, и это все равно не решит високосный год. Лично я бы использовал age() (см. мой ответ). 20.07.2011

  • 6

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

    24.08.2015

    7

    То, что вы пытаетесь сделать, это вручную извлечь информацию о человеке, который хотел бы использовать SQL, и отправить желание отдельно вручную. Что, если я предложу вам лучший подход?

    Извлеките детали пожеланий в формате Excel, и пусть приложение для пожеланий позаботится обо всем.

    Как минимум, вам понадобятся две вещи: файл Excel с деталями пожеланий (дата, имя, адрес электронной почты) и файл конфигурации (application.properties), и все, все готово. идти.

    Кроме того, существуют различные варианты локального запуска приложения (командная строка, передний план, фоновый , докер, планировщик окон, unix cron и т. д.) Облако.

    Приложение широко настраивается , вы можете настроить различные детали, такие как:

    • Параметры загрузки книги
    • Варианты изображений для отправки с пожеланиями.
    • SMTP-конфигурации
    • Другие конфигурации уровня приложения, например, когда отправлять пожелания, запоздалые пожелания, ведение журнала и т. д.

      Отказ от ответственности: я являюсь владельцем приложения

    20.06.2020
    Новые материалы

    Получение стоковых обновлений с помощью Python
    Для начинающего финансового аналитика Введение Описание: Этот проект Python создает скрипт для получения текущих обновлений акций с финансового веб-сайта Yahoo. Для этого проекта мы..

    Это все, что вам нужно знать о Kotlin в 2022 году
    Добро пожаловать! Kotlin — это язык программирования, популярность которого, кажется, растет, его действительно можно использовать для создания чего угодно, и если вы хотите узнать о Kotlin,..

    Текстовый графический интерфейс с Lanterna на Java
    Мой опыт работы с компьютерами (и текстовыми графическими пользовательскими интерфейсами) начался еще в восьмидесятых, когда я был ребенком, на дне рождения друга. Это был «новенький» Amstrad..

    Перезарядите свой мозг: умопомрачительный потенциал мозговых компьютерных интерфейсов
    Способность читать свои мысли и управлять объектами разумом долгое время были предметом человеческого любопытства, ограниченного областью научной фантастики… то есть до сих пор? С технологией,..

    Основы C# — Нулевой оператор объединения (??)
    Оператор ?? называется null-coalescing operator . Этот оператор используется для предоставления значения по умолчанию, если значение операнда в левой части оператора равно null ...

    Сравнение номеров версий в C++ с использованием синтаксического анализа строк
    Номера версий обычно используются для обозначения развития или обновлений программного обеспечения или любого другого продукта. При работе с номерами версий в C++ может быть полезно сравнить две..

    В мир искусственного интеллекта…
    ИИ — это новое топливо в современном мире. Куда бы вы ни обратились, с кем бы вы ни разговаривали — они, как правило, упоминают об ИИ хотя бы раз в ходе разговора. ИИ гудит повсюду. У каждого..