SQL Выберите предстоящие дни рождения
Я пытаюсь написать хранимую процедуру, чтобы выбрать сотрудников, у которых есть дни рождения, которые наступают.
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
Ответы
Ответ 1
Примечание. Я отредактировал это, чтобы исправить то, что, по моему мнению, было значительной ошибкой. Текущая версия для меня работает.
Это должно работать после изменения имен полей и таблиц, соответствующих вашей базе данных.
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. Таким образом, он возвращает все эти записи.
Ответ 2
Если кто-то все еще ищет решение в 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)
Ответ 3
Лучшее использование датированных и дат. Без округления, без аппроксимаций, без 29-го февраля, ничего, кроме функций даты
-
ageOfThePerson = DATEDIFF(yyyy,dateOfBirth, GETDATE())
-
dateOfNextBirthday = DATEADD(yyyy,ageOfThePerson + 1, dateOfBirth)
-
daysBeforeBirthday = DATEDIFF(d,GETDATE(), dateofNextBirthday)
Благодаря @Gustavo Cardoso новое определение возраста человека
-
ageOfThePerson = FLOOR(DATEDIFF(d,dateOfBirth, GETDATE())/365.25)
Ответ 4
Понравился подход @strelc, но его sql был немного выключен. Здесь обновленная версия, которая хорошо работает и проста в использовании:
SELECT * FROM User
WHERE (DATEDIFF(dd, getdate(), DATEADD(yyyy,
DATEDIFF(yyyy, birthdate, getdate()) + 1, birthdate)) + 1) % 366 <= <number of days>
изменить 10/2017: добавить один день в конец
Ответ 5
Извините, что не требовалось нейтрализовать год.
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)
Это должно работать.
Ответ 6
Я нашел решение для этого. Это может спасти кому-то драгоценное время.
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
Сделайте крест с датами и проверьте сравнение месяца и дат.
Ответ 7
Вы можете использовать функцию DAYOFYEAR
, но будьте осторожны, если хотите посмотреть январские дни рождения в декабре. Я думаю, вы будете в порядке, если диапазон дат, который вы ищете, не распространяется на Новый год.
Ответ 8
Это решение для MS SQL Server:
Он возвращает сотрудников с днями рождения в течение 30 дней.
SELECT * FROM rojstni_dnevi
WHERE (DATEDIFF (dd,
getdate(),
DATEADD ( yyyy,
DATEDIFF(yyyy, rDan, getdate()),
rDan)
nex )
+365) % 365 < 30
Ответ 9
Менее месяца:
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() ))))
Ответ 10
Мое предположение, что использование "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
Ответ 11
Вы можете использовать DATE_FORMAT для извлечения дневных и месячных частей дат рождения.
EDIT: извините, я не видел, что он не использовал MySQL.
Ответ 12
Предполагая, что это T-SQL, используйте DATEPART, чтобы сравнить месяц и дату отдельно.
http://msdn.microsoft.com/en-us/library/ms174420.aspx
В качестве альтернативы, вычитайте 1 января текущего года с каждого дня рождения, а затем сравните с использованием 1900 года (или независимо от того, какой у вас будет период вашей эпохи).
Ответ 13
Большинство из этих решений близки, но вы должны помнить несколько дополнительных сценариев. При работе с днями рождения и скользящей шкалой вы должны иметь возможность обрабатывать переход в следующий месяц.
Например, пример Stephens отлично подходит для дней рождения до последних 4 дней месяца. Тогда у вас есть логическая ошибка, так как действительные даты, если сегодня было 29, будут: 29, 30, а затем 1, 2, 3 из следующего месяца, так что вам тоже нужно это сделать.
Альтернативой будет синтаксический анализ даты с поля дня рождения и суб в текущем году, а затем выполнить стандартное сравнение диапазона.
Ответ 14
Еще одна мысль: добавьте свой возраст целыми годами к их дню рождения (или еще один, если их День рождения еще не произошел, а затем сравните, как вы делаете выше). Используйте DATEPART и DATEADD для этого.
http://msdn.microsoft.com/en-us/library/ms186819.aspx
В краевом случае диапазона, охватывающего год, должен быть специальный код.
Бонусный совет: рассмотрите возможность использования BETWEEN... AND вместо повторения операнда "День рождения".
Ответ 15
Это должно работать...
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))
Ответ 16
Я столкнулся с той же проблемой с моим проектом колледжа несколько лет назад. Я ответил (довольно ласковым образом), разделив год и дату (MM: DD) в двух отдельных столбцах. И до этого мой помощник по проекту просто получал все даты и программно просматривал их. Мы изменили это, потому что это было слишком неэффективно - не то, что мое решение было более элегантным. Кроме того, его, вероятно, невозможно сделать в базе данных, которая некоторое время используется несколькими приложениями.
Ответ 17
Попробуйте:
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)
Ответ 18
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() как дату-время, правильно?
Ответ 19
Предстоящий день рождения сотрудника - 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)
Ответ 20
Надеюсь, это поможет вам каким-то образом...
select Employeename,DOB
from Employeemaster
where day(Dob)>day(getdate()) and month(DOB)>=month(getDate())
Ответ 21
Это комбинация пары ответов, которые были протестированы. Это будет следующий следующий день после определенной даты и возраста. Кроме того, число дней будет ограничивать диапазон, который вы ищете 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
Ответ 22
Лучший способ добиться этого -
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)
Ответ 23
Я использовал это для 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');
Ответ 24
Я считаю, что этот билет был закрыт веками назад, но для получения правильного 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))
Ответ 25
Лучшее и простое решение:
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
Ответ 26
Это решение также заботится о днях рождения в следующем году и о заказе:
(dob = день рождения, bty = день рождения в этом году, nbd = следующий день рождения)
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
Ответ 27
Вы также можете использовать DATEPART
:
-- To find out Today 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))
Ответ 28
День рождения месяца
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)
Ответ 29
выберите BirthDate, Имя от сотрудников
порядок по делу
WHEN convert (nvarchar (5), BirthDate, 101) > convert (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) then 1 else 4 end, convert (nvarchar (2), BirthDate, 101), convert (nvarchar (2), BirthDate, 105)
Ответ 30
Попробуйте мое решение... У меня есть база данных 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)