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
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
27
0
57 262
34
Перейти к ответу Данный вопрос помечен как решенный

Ответы 34

Вы можете использовать ФОРМАТ ДАТЫ для извлечения части дня и месяца из дат дня рождения.

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

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

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

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

Crob 17.09.2008 18:08

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

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

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

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

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

Например, пример Стивенса отлично подходит для дней рождения до последних 4 дней месяца. Тогда у вас есть логическая ошибка, так как действительные даты, если бы сегодня было 29-е, были бы: 29, 30, И затем 1, 2, 3 СЛЕДУЮЩЕГО месяца, поэтому вы также должны выполнить условие для этого.

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

Повторите вашу последнюю альтернативу: это вызовет проблемы у тех, чей день рождения 29 февраля ...

erlando 17.09.2008 18:29

Ах да, это тоже вопрос, который стоит рассмотреть.

Mitchel Sellers 17.09.2008 18:52

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

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

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

Бонусный совет: рассмотрите возможность использования BETWEEN ... AND вместо повторения операнда Birthday.

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

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)

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

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

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))
Ответ принят как подходящий

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

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

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

Я не уверен, как отредактировать ваш ответ, но вместо деления на 365 вам нужно разделить на 365,25, а затем привести к int. Високосный год, опять все лажаю.

Crob 17.09.2008 18:51

Спасибо, вы абсолютно правы, и у меня там тоже был баг. Возможность редактировать посты других людей дает определенный балл репутации. Проверьте эту ссылку: stackoverflow.com/questions/18557/…

JosephStyons 17.09.2008 18:55

Нашел более свежий ответ снизу, который мне больше понравился, подумал, что поделюсь: SELECT * FROM User WHERE (DATEDIFF (dd, getdate (), DATEADD (yyyy, DATEDIFF (yyyy, Birthdate, getdate ()), Birthdate)) + 365)% 365 <= <количество дней>

Edyn 26.05.2012 01:13

@Edyn: Прекрасно! но немного неаккуратно ;-)

W.K.S 26.06.2012 17:00

Предыдущий комментарий немного отключен для очень конкретных нечастых дат ... вот исправление: SELECT * FROM User WHERE (DATEDIFF (dd, getdate (), DATEADD (yyyy, DATEDIFF (yyyy, Birthdate, getdate ()) + 1, дата рождения)))% 366 <= <количество дней>

Edyn 30.12.2013 19:20

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

Попробуйте:

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)

Лучшее использование датированных и 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)

То, как вы рассчитываете возраст человека, неверно. Это потому, что вы различаете только год. Таким образом, если кто-то родился 12/1990, а мы - 04/2010, возраст человека будет рассчитан как 30 лет.

Gustavo Cardoso 22.12.2010 21:07

у этого метода есть некоторые проблемы, попробуйте использовать следующий сценарий: <br/> <br/> DECLARE thisJoiningDate DATE = '2011-12-05' <br/> DECLARE EmploymentDuration DECIMAL (18,2) <br/> DECLARE DateOfNextAnniversary DATE < br /> DECLARE DaysBeforeAnniversary INT <br/> <br/> SET EmploymentDuration = DATEDIFF (MONTH, thisJoiningDate, GETDATE ()) <br/> SET DateOfNextAnniversary = DATEADD (MONTH, EmploymentDuration + 12, thisJoiningDate) <br/> SET DaysBeforeAnniversary = DATEDIFF (dd, GETDATE (), DateOfNextAnniversary) <br/> <br/> ВЫБЕРИТЕ thisJoiningDate, EmploymentDuration, DateOfNextAnniversary, DaysBeforeAnniversary

Talha Ashfaque 18.11.2012 17:08

@tjaank, попробовал, а где дополнительная проблема? И в вопросе нет таких понятий, как EmploymentDuration или JoiningDate.

Philippe Grondier 20.11.2012 14:43

@ Густаво Кардосо, к моему удивлению, ты прав! Я обновил ответ соответственно

Philippe Grondier 20.11.2012 16:00

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

Я придумал:

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 () как datetime, верно?

Ближайший день рождения сотрудника - 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)

Надеюсь, это поможет тебе в какой-то мере ....

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

можешь добавить пояснение?

Adrian Cid Almaguer 04.07.2015 05:40

Это комбинация пары проверенных ответов. Это найдет следующий день рождения после определенной даты и возраст, в котором они будут. Также число дней ограничивает диапазон, который вы ищете, 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

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

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)

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

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

Пришлось немного повозиться с запросом, но работает как шарм. Вот обновление (тоже добавлю в качестве ответа): ВЫБРАТЬ * ОТ ПОЛЬЗОВАТЕЛЯ WHERE (DATEDIFF (dd, getdate (), DATEADD (yyyy, DATEDIFF (yyyy, Birthdate, getdate ()), Birthdate)) + 365)% 365 <= 30

Edyn 26.05.2012 00:58

Первый комментарий немного не подходит для очень конкретных, нечастых дат ... вот исправление: SELECT * FROM User WHERE (DATEDIFF (dd, getdate (), DATEADD (yyyy, DATEDIFF (yyyy, Birthdate, getdate ()) + 1, дата рождения)))% 366 <= <количество дней>

Edyn 30.12.2013 19:19

Попробуйте мое решение ... У меня есть база данных 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)

Если кто-то все еще ищет решение в 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)

Большое спасибо за этот перевод mysql! : D

Ryan Fletcher 27.05.2016 19:54

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

 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

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

Я использовал это для 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');

Я считаю, что этот билет был закрыт много лет назад, но для получения правильного запроса 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))

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

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

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

Это ошибочно. Учитывая текущую дату 2015-03-01 и дату рождения 2012-02-29, результат будет 364. Добавление 364 дней к 2012-02-29 дает 2013-02-27, что неверно, так как оно должно быть возвращено как 2013-02-28.

rrrr 26.11.2013 12:58

@rrrr Вы думаете об этом задом наперед ... это должно быть 2015-03-01 + 364, то есть 28.02.2016. Однако вы были правы в том, что в нем был изъян, поскольку он смотрел в прошлое в високосные годы, а не в будущее. Я настроил его, чтобы он работал правильно.

Edyn 27.11.2013 23:22

@Edyn Приведенный ниже выбор возвращает 365, похоже, он отключен на день: code DECLARE @Date DATE = '2018-2-28', @BirthDate DATE = '1960-02-29', @DaysFromBirthDate INT = 0 SELECT DATEDIFF (dd, @Date, DATEADD (yyyy, DATEDIFF (yyyy, @BirthDate, @Date) + 1, @BirthDate))% 366 code

user3800174 19.10.2017 16:42

@ user3800174 Технически это правильно. Поскольку в 2018 году нет високосного года, предполагается, что день рождения - 28-е число, и выполняется поиск следующего, соответствующего 28 февраля 2019 года, до которого осталось 365 дней. Если вы запустите тот же запрос, но укажите 2020-02-28 в качестве дня рождения, вы получите 0, что является правильным.

Edyn 19.10.2017 19:34

Таким образом, использование 1960-02-28 также возвращает 365, что неверно, кажется, что они отключены на один день :) codeDECLARE @Date DATE = '2018-2-28', @BirthDate DATE = '1960-02- 28 ', @DaysFromBirthDate INT = 0 SELECT DATEDIFF (dd, @Date, DATEADD (yyyy, DATEDIFF (yyyy, @BirthDate, @Date) + 1, @BirthDate))% 366 code

user3800174 19.10.2017 21:54

Я понимаю, что вы имеете в виду ... отредактировано, чтобы добавить один день в конец расчета. Это должно решить проблему.

Edyn 21.10.2017 02:09

Возможно, вы имели в виду дату рождения)) + 1)% 366?

user3800174 24.10.2017 18:26

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

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

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

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

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

Это решение также учитывает дни рождения в следующем году и порядок: (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

Вы также можете использовать 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))

Я предполагаю, что использование «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

День рождения текущего месяца

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)

select BirthDate,Name from Employees 
order by 
Case WHEN convert(nvarchar(5),BirthDate,101) > convert(nvarchar(5),GETDATE(),101) 
     then 2 
     WHEN convert(nvarchar(5),BirthDate,101) < convert(nvarchar(5),GETDATE(),101) 
     then 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)

Пожалуйста, объясните, как ваш код решает проблему. И, пожалуйста, отформатируйте свой код.

Julien Lopez 22.09.2016 14:43

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

SELECT 
    Employee.DOB,
    DATEADD(
                mm, 
                (
                    (
                        (
                            (
                                DATEPART(yyyy, getdate())-DATEPART(yyyy, Employee.DOB )
                            )
                            +
                            (
                                1-
                                (
                                    ((DATEPART(mm, Employee.DOB)*100)+DATEPART(dd, Employee.DOB))
                                    /
                                    ((DATEPART(mm, getdate())*100) + DATEPART(dd, getdate()))
                                )
                            )
                        )
                    *12
                    )
                ), 
                Employee.DOB
            ) NextDOB
FROM 
    Employee 
ORDER BY 
    NextDOB ;

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

Решение для SQLite3:

SELECT
    *, 
    strftime('%j', birthday) - strftime('%j', 'now') AS days_remaining
FROM
    person
WHERE :n_days >= CASE
    WHEN days_remaining >= 0 THEN days_remaining
    ELSE days_remaining + strftime('%j', strftime('%Y-12-31', 'now'))
    END
;

Решения деления на 325,25 для получения возраста или переноса даты рождения на текущий год и т. д. У меня не работали. Это вычисляет дельту двух daysOfTheYear (1-366). Если день рождения еще не наступил в этом году, вы автоматически получите правильное количество оставшихся дней, с которым можете сравнить. Если день рождения уже наступил, «Осталось_дней» будет отрицательным, и вы можете получить правильное количество оставшихся дней, все равно добавив общее количество дней в текущем году. Это также правильно обрабатывает високосные годы, поскольку в этом случае также будет добавлен дополнительный день (с помощью dayOfYear (31 декабря)).

Другие вопросы по теме