2008-09-17 4 views
22

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

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 

ответ

29

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

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

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. Таким образом, он возвращает все эти записи.

+4

Я не уверен, как отредактировать ваш ответ, но вместо того, чтобы делить на 365, вам нужно разделить на 365.25, а затем бросить на int. Високосный год, снова закручивая все. – Crob 2008-09-17 14:51:35

+2

Спасибо, ты совершенно прав, и там тоже была ошибка. Возможность редактировать сообщения других людей имеет определенный рейтинг репутации. Проверьте эту ссылку: http://stackoverflow.com/questions/18557/how-does-stackoverflow-work-the-unofficial-faq – JosephStyons 2008-09-17 14:55:17

+0

Очень приятно, спасибо – Magpie 2012-01-10 15:39:55

0

Вы можете использовать DATE_FORMAT извлечь месяц и день части даты рождения.

EDIT: извините, я не видел, что он не использовал MySQL.

-2

Лучше, добавить разницу в годах до даты РОЖДЕНИЯ, чтобы сделать все, что в этом году, а затем сделать ваш сравнивает

SELECT * FROM Employees WHERE 
    DATEADD (year, YEAR(@Today) - YEAR(@Birthday), birthday) BETWEEN @Today AND @EndDate 
+0

Это близко, но что, если это было в конце месяца или года. Скажем сегодня, 27 декабря, и я хочу, чтобы дни рождения были в течение следующих 2 недель. – Crob 2008-09-17 14:08:19

1

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

0

Предполагая, что это T-SQL, используйте DATEPART для сравнения месяца и даты отдельно.

http://msdn.microsoft.com/en-us/library/ms174420.aspx

В качестве альтернативы, вычтите 1 января текущего года со дня рождения каждого, а затем сравнить с использованием 1900 года (или что-то ваша эпоха год).

0

Большинство из этих решений близки, но вы должны помнить несколько дополнительных сценариев. При работе с днями рождения и скользящей шкалой вы должны иметь возможность обрабатывать переход в следующий месяц.

Например, пример Стивенса отлично подходит для дней рождения до последних 4 дней месяца. Тогда у вас есть логическая ошибка, поскольку действительные даты, если сегодня было 29-й, будут: 29, 30, а затем 1, 2, 3 из следующего месяца, так что вам тоже нужно это условие.

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

+0

Повторите свою последнюю альтернативу: это вызовет проблемы с теми, чей день рождения - 29 февраля ... – erlando 2008-09-17 14:29:01

+0

А да, это тоже будет проблемой. – 2008-09-17 14:52:17

0

Еще одна мысль:. Добавить свой возраст в целом годы их рождения (или один больше, если их день рождения еще не произошло, а затем сравнить, как вы выше Используйте DATEPART и DATEADD сделать это

http://msdn.microsoft.com/en-us/library/ms186819.aspx

.

кромка случай диапазона, охватывающего год будет иметь специальный код

Дополнительный совет. рассмотреть возможность использования BETWEEN ... И вместо того, чтобы повторять операнд рождения.

2

К сожалению, не требовалось нейтрализовать год.

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) 

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

0

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

DECLARE @endDate DATETIME 
DECLARE @today DATETIME 

SELECT @endDate = getDate()+6, @today = getDate() 

SELECT * FROM Employees 
    WHERE 
    (DATEPART (month, birthday) >= DATEPART (month, @today) 
     AND DATEPART (day, birthday) >= DATEPART (day, @today)) 
    AND 
    (DATEPART (month, birthday) < DATEPART (month, @endDate) 
     AND DATEPART (day, birthday) < DATEPART (day, @endDate)) 
0

Я столкнулся с той же проблемой с моим проектом колледжа несколько лет назад. Я ответил (довольно ласковым образом), разделив год и дату (MM: DD) в двух отдельных столбцах. И до этого мой помощник по проекту просто получал все даты и программно просматривал их. Мы изменили это, потому что это было слишком неэффективно - не то, что мое решение было более элегантным. Кроме того, его, вероятно, невозможно сделать в базе данных, которая некоторое время используется несколькими приложениями.

0

Дайте этому попытку:

SELECT * FROM Employees 
WHERE DATEADD(yyyy, DATEPART(yyyy, @Today)-DATEPART(yyyy, Birthday), Birthday) > @Today 
AND DATEADD(yyyy, DATEPART(yyyy, @Today)-DATEPART(yyyy, Birthday), Birthday) < DATEADD(dd, @NumDays, @Today) 
8

Лучшее использование DateDiff и DateAdd. Нет округления, не аппроксимирует, не 29 февраля жука, ничего, кроме даты функций

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

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

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

Благодаря @Gustavo Кардозо, новый

  1. ageOfThePerson = FLOOR(DATEDIFF(d,dateOfBirth, GETDATE())/365.25)
0

Nuts! Хорошее решение между тем, когда я начал думать об этом, и когда я вернулся, чтобы ответить. :)

я придумал:

select (365 + datediff(d,getdate(),cast(cast(datepart(yy,getdate()) as varchar(4)) + '-' + cast(datepart(m,birthdt) as varchar(2)) + '-' + cast(datepart(d,birthdt) as varchar(2)) as datetime))) % 365 
from employees 
where (365 + datediff(d,getdate(),cast(cast(datepart(yy,getdate()) as varchar(4)) + '-' + cast(datepart(m,birthdt) as varchar(2)) + '-' + cast(datepart(d,birthdt) as varchar(2)) as datetime))) % 365 < @NumDays 

Вам не нужно бросить GETDATE() в качестве даты-времени, не так ли?

0

Предстоящий День рождения для работника - SQLSERVER

DECLARE @sam TABLE 
(
    EmployeeIDs  int, 
    dob   datetime 
) 
INSERT INTO @sam (dob, EmployeeIDs) 
SELECT DOBirth, EmployeeID FROM Employee 

SELECT * 
FROM 
(
    SELECT *, bd_this_year = DATEADD(YEAR, DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, dob), dob) 
    FROM @sam s 
) d 
WHERE d.bd_this_year > DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0) 
AND d.bd_this_year <= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 3) 
0

Я надеюсь, что это помогает U в некотором роде ....

select Employeename,DOB 
from Employeemaster 
where day(Dob)>day(getdate()) and month(DOB)>=month(getDate()) 
0

Это сочетание нескольких ответов, которые были испытаны , Это будет следующий следующий день после определенной даты и возраста. Также NUMDAYS будет ограничивать диапазон вы хотите 7 дней = неделя и т.д.

SELECT DISTINCT FLOOR(DATEDIFF(dd,Birthday, @BeginDate)/365.25) + 1 age, 
DATEADD(yyyy, FLOOR(DATEDIFF(dd,Birthday, @BeginDate)/365.25) + 1, Birthday) nextbirthday, birthday 
FROM   table 
WHERE  DATEADD(yyyy, FLOOR(DATEDIFF(dd,Birthday, @BeginDate)/365.25) + 1, Birthday) > @BeginDate 
AND DATEADD(yyyy, FLOOR(DATEDIFF(dd,Birthday, @BeginDate)/365.25) + 1, Birthday) < DATEADD(dd, @NumDays, @BeginDate) 
order by nextbirthday 
0

Лучший способ добиться того же является

DECLARE @StartDate DATETIME 
DECLARE @EndDate DATETIME 

SELECT Member.* from vwMember AS Member 
WHERE (DATEADD(YEAR, (DATEPART(YEAR, @StartDate) - 
         DATEPART(YEAR, Member.dBirthDay)), Member.dBirthDay) 
BETWEEN @StartDate AND @EndDate) 
1

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

SELECT * FROM rojstni_dnevi 
    WHERE (DATEDIFF (dd, 
        getdate(), 
        DATEADD ( yyyy, 
           DATEDIFF(yyyy, rDan, getdate()), 
           rDan) 
    nex   ) 
     +365) % 365 < 30 
-1

Попробуйте мое решение ... У меня есть база данных Informix ...

SELECT person, year(today)-year(birthdate) as years, birthdate, 

CASE 
WHEN MOD(year(birthdate)+((year(today)-year(birthdate))+1),4)<>0 AND MONTH(birthdate)=2 AND DAY(birthdate)=29 THEN 
    CASE 
    WHEN mdy(month(birthdate), 28, year(birthdate)+((year(today)-year(birthdate))+1))-today >= 365 THEN (mdy(month(birthdate), 28, year(birthdate)+((year(today)-year(birthdate))+1))-today)-365 
    WHEN mdy(month(birthdate), 28, year(birthdate)+((year(today)-year(birthdate))+1))-today < 365 THEN mdy(month(birthdate), 28, year(birthdate)+((year(today)-year(birthdate))+1))-today 
    END 
ELSE 
    CASE 
    WHEN mdy(month(birthdate), day(birthdate), year(birthdate)+((year(today)-year(birthdate))+1))-today >= 365 THEN (mdy(month(birthdate), day(birthdate), year(birthdate)+((year(today)-year(birthdate))+1))-today)-365 
    WHEN mdy(month(birthdate), day(birthdate), year(birthdate)+((year(today)-year(birthdate))+1))-today < 365 THEN mdy(month(birthdate), day(birthdate), year(birthdate)+((year(today)-year(birthdate))+1))-today 
    END 
END until 

FROM table_name 
WHERE mdy(month(birthdate), day(birthdate), 2000) >= mdy(month(today), day(today), 2000) 
AND mdy(month(birthdate), day(birthdate), 2000) <= mdy(month(today), day(today), 2000)+30 
OR 
mdy(month(birthdate), day(birthdate), 2000) <= mdy(month(today), day(today), 2000)-(365-30) 
ORDER BY 4, YEAR(birthdate) 
12

В случае, если кто-то все еще ищет решение в 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) 
2

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

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 @[email protected] + 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 @[email protected] + 1 

END 

    RETURN 
END 

Сделать перекрестное соединение датами и сравнить их количество и даты.

0

Я использовал это для MySQL, возможно, не самый эффективный способ запроса, но достаточно простой для реализации.

select * from `schema`.`table` where date_format(birthday,'%m%d') >= date_format(now(),'%m%d') and date_format(birthday,'%m%d') < date_format(DATE_ADD(NOW(), INTERVAL 5 DAY),'%m%d'); 
0

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

SELECT Employee_Name, DATE_OF_BIRTH 
FROM Hr_table 
WHERE 

/** 
fetching the original birth_date and replacing the birth year to the current but have to deduct 7 days to adjust jan 1-7 birthdate. 
**/ 

datediff(d,getdate(),DATEADD(year,datediff(year,DATEADD(d,-7,hr.DATE_OF_BIRTH),getdate()),hr.date_of_birth)) between 0 and 7 

-- current date looks ahead to 7 days for upcoming modified year birth date. 

order by 

-- sort by no of days before the birthday 
datediff(d,getdate(),DATEADD(year,datediff(year,DATEADD(d,-7,hr.DATE_OF_BIRTH),getdate()),hr.date_of_birth)) 
3

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

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

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

-1
CREATE PROCEDURE [dbo].[P_EmployeesGetBirths] 
     @Date Date, 
     @Days int 
    as 
    Begin 
     SET NOCOUNT ON; 

     Declare 
      @From int = Month(@Date) * 100 + Day(@Date), 
      @To int = Month(DateAdd(DD, @Days, @Date)) * 100 + Day(DateAdd(DD, @Days, @Date)), 
      @NeutralDate Date = Cast('1900-'+cast(Month(@Date) as nvarchar(2))+'-' + cast(Day(@Date) as nvarchar(2)) as Date) 

     Select 
      DOB, 
      DATEADD(DD, DateDiff(DD, @NeutralDate, DateAdd(YY, 1900-Year(DOB), DOB)), @Date) OnDate 
     From 
      Employees(nolock) 
     Where 
      DOB is not null and 
      Month(DOB) * 100 + Day(DOB) between @From and @To 
     order by 
      Month(DOB) * 100 + Day(DOB) 
    End 
    Go 
0

Лучше и простое решение:

select * from users with(nolock) 
where date_of_birth is not null 
and 
(
     DATEDIFF(dd, 
        DATEADD(yy, -(YEAR(GETDATE())-1900),GETDATE()), --Today 
        DATEADD(yy, -(YEAR(date_of_birth)-1901),date_of_birth) 
    ) % 365 
) = 30 
1

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

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())))) 
0

Это решение также заботится о днях рождения в следующем году и о заказе: (dob = день рождения; bty = день рождения в этом году; окр = следующий день рождения)

with rs (bty) as (
    SELECT DATEADD(Year, DATEPART(Year, GETDATE()) - DATEPART(Year, dob), dob) as bty FROM Employees 
), 
rs2 (nbd) as (
    select case when bty < getdate() then DATEADD(yyyy, 1, bty) else bty end as nbd from rs 
) 
select nbd, DATEDIFF(d, getdate(), nbd) as diff from rs2 where DATEDIFF(d, getdate(), nbd) < 14 order by diff 

Эта версия, которая позволяет избежать сравнения дат, может быть быстрее:

with rs (dob, bty) as (
    SELECT dob, DATEADD(Year, DATEPART(Year, GETDATE()) - DATEPART(Year, DOB), DOB) as bty FROM employee 
), 
rs2 (dob, nbd) as (
    select dob, DATEADD(yyyy, FLOOR(ABS((-1*(SIGN(DATEDIFF(d, getdate(), bty))))+0.1)), bty) as nbd from rs 
), 
rs3 (dob, diff) as (
    select dob, datediff(d, getdate(), nbd) as diff from rs2 
) 
select dob, diff from rs3 where diff < 14 order by diff 

Если диапазон охватывает 29 февраля в следующем году, а затем использовать:

with rs (dob, ydiff) as (
    select dob, DATEPART(Year, GETDATE()) - DATEPART(Year, DOB) as ydiff from Employee 
), 
rs2 (dob, bty, ydiff) as (
    select dob, DATEADD(Year, ydiff, dob) as bty, ydiff from rs 
), 
rs3 (dob, nbd) as (
    select dob, DATEADD(yyyy, FLOOR(ABS((-1*(SIGN(DATEDIFF(d, getdate(), bty))))+0.1)) + ydiff, dob) as nbd from rs2 
), 
rs4 (dob, ddiff, nbd) as (
    select dob, datediff(d, getdate(), nbd) as diff, nbd from rs3 
) 
select dob, nbd, ddiff from rs4 where ddiff < 68 order by ddiff 
0

Вы можете также использовать DATEPART:

-- To find out Today's Birthday 
DECLARE @today DATETIME 
SELECT @today = getdate() 

SELECT * 
FROM SMIS_Registration 
WHERE (DATEPART (month, DOB) >= DATEPART (month, @today) 
     AND DATEPART (day, DOB) = DATEPART (day, @today)) 
1

Мое предположение, что использование «365.25» скоро или поздно потерпит неудачу.

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

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

тест с 2016 года и 2116, и вы увидите разницу. Я могу опубликовать только одну ссылку, но изменить de/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 
0

Текущих месяцы рождения

SELECT * FROM tblMember m 
WHERE m.GDExpireDate != '' 
AND CONVERT(CHAR(2),CONVERT(datetime, m.dob, 103), 101) = CONVERT(CHAR(2), GETDATE(), 101)  
AND CONVERT(CHAR(2),CONVERT(datetime, m.dob, 103), 103) >= CONVERT(CHAR(2), GETDATE(), 103) 
0

выберите BirthDate, имя из сотрудников порядка по делу Когда новообращенный (NVARCHAR (5), BirthDate, 101)> преобразующих (NVARCHAR (5), GETDATE (), 101), затем 2 WHEN convert (nvarchar (5), BirthDate, 101) < convert (nvarchar (5), GETDATE(), 101), затем 3 WHEN convert (nvarchar (5), BirthDate, 101) = convert (nvarchar (5), GETDATE(), 101), затем 1 else 4 end, convert (nvarchar (2), BirthDate, 101), convert (nvarchar (2), BirthDate, 105)

Смежные вопросы