SQL выберите предстоящие дни рождения - PullRequest
23 голосов
/ 17 сентября 2008

Я пытаюсь написать хранимую процедуру для выбора сотрудников с предстоящими днями рождения.

SELECT * FROM Employees WHERE Birthday > @Today AND Birthday < @Today + @NumDays

Это не сработает, потому что год рождения является частью Дня Рождения, поэтому, если мой день рождения был '09 -18-1983 ', это не будет между '09 -18-2008' и '09 -25-2008 '.

Есть ли способ игнорировать часть года в полях даты и сравнивать месяц / день?

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

Вот рабочее решение, которое я в итоге создал, спасибо Kogus.

SELECT * FROM Employees 
WHERE Cast(DATEDIFF(dd, birthdt, getDate()) / 365.25 as int)
    - Cast(DATEDIFF(dd, birthdt, futureDate) / 365.25 as int) 
<> 0

Ответы [ 34 ]

31 голосов
/ 17 сентября 2008

Примечание: я отредактировал это, чтобы исправить, как мне кажется, существенную ошибку. Текущая версия работает для меня.

Это должно работать после того, как вы измените имена полей и таблиц, чтобы они соответствовали вашей базе данных.

SELECT 
  BRTHDATE AS BIRTHDAY
 ,FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()) / 365.25) AS AGE_NOW
 ,FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()+7) / 365.25) AS AGE_ONE_WEEK_FROM_NOW
FROM 
  "Database name".dbo.EMPLOYEES EMP
WHERE 1 = (FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()+7) / 365.25))
          -
          (FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()) / 365.25))

По сути, он получает количество дней от дня рождения до настоящего момента и делит их на 365 (чтобы избежать проблем округления, возникающих при непосредственном преобразовании в годы).

Затем он получает количество дней от дня рождения до недели и делит их на 365, чтобы узнать возраст в неделю.

Если их день рождения находится в пределах недели, тогда разница между этими двумя значениями будет равна 1. Таким образом, он возвращает все эти записи.

13 голосов
/ 20 апреля 2011

Если кто-то все еще ищет решение в MySQL (немного другие команды), вот запрос:

SELECT
 name,birthday,
 FLOOR(DATEDIFF(DATE(NOW()),birthday) / 365.25) AS age_now,
 FLOOR(DATEDIFF(DATE_ADD(DATE(NOW()),INTERVAL 30 DAY),birthday) / 365.25) AS age_future

FROM user

WHERE 1 = (FLOOR(DATEDIFF(DATE_ADD(DATE(NOW()),INTERVAL 30 DAY),birthday) / 365.25)) - (FLOOR(DATEDIFF(DATE(NOW()),birthday) / 365.25))

ORDER BY MONTH(birthday),DAY(birthday)
8 голосов
/ 17 сентября 2008

Лучшее использование datediff и dateadd. Без округления, без приблизительных значений, без ошибок 29 февраля, только функции даты

  1. ageOfThePerson = DATEDIFF(yyyy,dateOfBirth, GETDATE())

  2. dateOfNextBirthday = DATEADD(yyyy,ageOfThePerson + 1, dateOfBirth)

  3. daysBeforeBirthday = DATEDIFF(d,GETDATE(), dateofNextBirthday)

Благодаря @Gustavo Cardoso, новое определение для возраста человека

  1. ageOfThePerson = FLOOR(DATEDIFF(d,dateOfBirth, GETDATE())/365.25)
3 голосов
/ 26 мая 2012

Понравился подход @strelc, но его sql немного отключился. Вот обновленная версия, которая хорошо работает и проста в использовании:

SELECT * FROM User 
WHERE (DATEDIFF(dd, getdate(), DATEADD(yyyy, 
    DATEDIFF(yyyy, birthdate, getdate()) + 1, birthdate)) + 1) % 366 <= <number of days>

редактировать 10/2017: добавить один день до конца

2 голосов
/ 17 сентября 2008

Извините, не вижу необходимости нейтрализовать год.

select * from Employees
where DATEADD (year, DatePart(year, getdate()) - DatePart(year, Birthday), Birthday)
      between convert(datetime, getdate(), 101) 
              and convert(datetime, DateAdd(day, 5, getdate()), 101)

Это должно работать.

2 голосов
/ 30 ноября 2011

Я нашел решение для этого. Это может сэкономить кому-то драгоценное время.

 select EmployeeID,DOB,dates.date  from emp_tb_eob_employeepersonal 
 cross join dbo.GetDays(Getdate(),Getdate()+7) as dates where weekofmonthnumber>0
 and month(dates.date)=month(DOB) and day(dates.date)=day(DOB)



GO
/****** Object:  UserDefinedFunction [dbo].[GetDays]    Script Date: 11/30/2011 13:19:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--SELECT [dbo].[GetDays] ('02/01/2011','02/28/2011')

ALTER FUNCTION [dbo].[GetDays](@startDate datetime, @endDate datetime)
RETURNS @retValue TABLE
(Days int ,Date datetime, WeekOfMonthNumber int, WeekOfMonthDescription varchar(10), DayName varchar(10))
AS
BEGIN
    DECLARE @nextDay int
    DECLARE @nextDate datetime 
    DECLARE @WeekOfMonthNum int 
    DECLARE @WeekOfMonthDes varchar(10) 
    DECLARE @DayName varchar(10) 
    SELECT @nextDate = @startDate, @WeekOfMonthNum = DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH,0,@startDate),0),@startDate) + 1, 
    @WeekOfMonthDes = CASE @WeekOfMonthNum 
        WHEN '1' THEN 'First' 
        WHEN '2' THEN 'Second' 
        WHEN '3' THEN 'Third' 
        WHEN '4' THEN 'Fourth' 
        WHEN '5' THEN 'Fifth' 
        WHEN '6' THEN 'Sixth' 
        END, 
    @DayName 
    = DATENAME(weekday, @startDate)
SET @nextDay=1
WHILE @nextDate <= @endDate 
BEGIN 
    INSERT INTO @retValue values (@nextDay,@nextDate, @WeekOfMonthNum, @WeekOfMonthDes, @DayName) 
    SELECT @nextDay=@nextDay + 1 
SELECT @nextDate = DATEADD(day,1,@nextDate), 
    @WeekOfMonthNum 
    = DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH,0, @nextDate),0), @nextDate) + 1, 
    @WeekOfMonthDes 
    = CASE @WeekOfMonthNum 
    WHEN '1' THEN 'First' 
    WHEN '2' THEN 'Second' 
    WHEN '3' THEN 'Third' 
    WHEN '4' THEN 'Fourth' 
    WHEN '5' THEN 'Fifth' 
    WHEN '6' THEN 'Sixth' 
    END, 
    @DayName 
    = DATENAME(weekday, @nextDate) 
    CONTINUE 
END 

WHILE(@nextDay <=31)
BEGIN


    INSERT INTO @retValue values (@nextDay,@nextDate, 0, '', '') 
    SELECT @nextDay=@nextDay + 1

END

    RETURN
END

Создайте перекрестное соединение с датами и проверьте сравнение месяца и дат.

2 голосов
/ 17 сентября 2008

Вы можете использовать функцию DAYOFYEAR, но будьте осторожны, когда хотите узнать дни рождения в январе в декабре. Я думаю, что у вас все будет хорошо, если диапазон дат, который вы ищете, не охватывает Новый год.

2 голосов
/ 01 февраля 2016

Я предполагаю, что использование "365.25" рано или поздно закончится неудачей.

Итак, я тестирую рабочий раствор, используя «365.25» И это не возвращает одинаковое количество строк для каждого случая. Вот пример:

http://sqlfiddle.com/#!3/94c3ce/7

тест с 2016 и 2116 годами, и вы увидите разницу. Я могу опубликовать только одну ссылку, но изменить / 7 на / 8, чтобы увидеть оба запроса. (/ 10 и / 11 для первого ответа)

Итак, я предлагаю этот другой запрос, в котором точка определяется на следующий день рождения с начальной даты, а затем сравнивает, находится ли она в моем диапазоне интересов.

SELECT * FROM Employees 
WHERE 
CASE WHEN (DATEADD(yyyy,DATEDIFF(yyyy, birthdt, @fromDate),birthdt) < @fromDate )
THEN DATEADD(yyyy,DATEDIFF(yyyy, birthdt, @fromDate)+1,birthdt)
ELSE DATEADD(yyyy,DATEDIFF(yyyy, birthdt, @fromDate),birthdt) END
BETWEEN @fromDate AND @toDate
1 голос
/ 10 ноября 2010

Это решение для MS SQL Server: Возвращает сотрудников с днями рождения через 30 дней.

SELECT * FROM rojstni_dnevi
  WHERE (DATEDIFF   (dd, 
                    getdate(), 
                    DATEADD (   yyyy, 
                                DATEDIFF(yyyy, rDan, getdate()),
                                rDan)
    nex             )
        +365) % 365 < 30
1 голос
/ 21 ноября 2014

Менее чем за месяц:

SELECT * FROM people WHERE MOD( DATEDIFF( CURDATE( ) , `date_birth`) /30, 12 ) <1 and (((month(`date_birth`)) = (month(curdate())) and (day(`date_birth`)) > (day (curdate() ))) or ((month(`date_birth`)) > (month(curdate())) and (day(`date_birth`)) < (day (curdate() ))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...