web-dev-qa-db-fra.com

Anniversaires à venir SQL Select

J'essaie d'écrire une procédure stockée pour sélectionner les employés qui ont des anniversaires à venir. 

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

Cela ne fonctionnera pas car l'année de naissance fait partie de l'anniversaire. Par conséquent, si mon anniversaire était '09 -18-1983 ', il ne tombera pas entre '09 -18-2008' et '09 -25-2008 '. 

Existe-t-il un moyen d'ignorer la partie année des champs de date et de simplement comparer mois/jours? 

Cette opération aura lieu tous les lundis matins pour alerter les responsables des anniversaires à venir, de sorte qu’elle couvrira probablement les années à venir. 

Voici la solution de travail que j'ai finalement créée, merci Kogus. 

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

Note: J'ai édité cela pour corriger ce qui, à mon avis, était un bug important. La version actuellement affichée fonctionne pour moi.

Cela devrait fonctionner une fois que vous avez modifié les noms de champs et de tables afin qu'ils correspondent à votre base de données.

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

En gros, il obtient le nombre de jours de son anniversaire à maintenant et le divise par 365 (pour éviter les problèmes d'arrondi lorsque vous convertissez directement en années).

Ensuite, il passe le nombre de jours de leur anniversaire à une semaine à partir de maintenant et le divise par 365 pour obtenir leur âge une semaine à partir de maintenant.

Si leur date de naissance est dans une semaine, la différence entre ces deux valeurs sera égale à 1. Elle renvoie donc tous ces enregistrements.

30
JosephStyons

Si quelqu'un cherche toujours une solution dans MySQL (commandes légèrement différentes), voici la requête:

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)
12
Andres SK

Meilleure utilisation de datiff et dateadd. Pas d'arrondi, pas d'approximation, pas de bug du 29 février, rien que des fonctions de date

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

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

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

Grâce à @Gustavo Cardoso, nouvelle définition de l'âge de la personne

  1. ageOfThePerson = FLOOR(DATEDIFF(d,dateOfBirth, GETDATE())/365.25)
8
Philippe Grondier

A aimé l'approche de @strelc, mais son sql était un peu en retrait. Voici une version mise à jour qui fonctionne bien et est simple à utiliser:

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

edit 10/2017: ajouter un jour à la fin

3
Edyn

J'ai trouvé la solution pour cela. Cela peut sauver le temps précieux de quelqu'un.

 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

Faites un croisement avec les dates et vérifiez la comparaison du mois et des dates.

2
Jovial

Vous pouvez utiliser la fonction DAYOFYEAR mais soyez prudent lorsque vous souhaitez rechercher les anniversaires de janvier en décembre. Je pense que tout ira bien tant que la plage de dates que vous recherchez ne couvre pas le Nouvel An.

2
Dave Webb

À mon avis, utiliser "365.25" tôt ou tard serait un échec.

J'ai donc testé la solution de travail en utilisant "365.25" Et elle ne renvoie pas le même nombre de lignes pour chaque cas. Voici un exemple:

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

testez avec les années 2016 et 2116 et vous verrez la différence. Je ne peux publier qu'un seul lien mais changer de/7 par/8 pour voir les deux requêtes. (/ 10 et/11 pour la première réponse)

Donc, je suggère cette autre requête, où le point est déterminé le prochain anniversaire de naissance à partir d’une date de début, puis compare si c’est dans mon domaine d’intérêt.

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
2
Fede H

Désolé n'a pas vu l'obligation de neutraliser l'année.

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)

Cela devrait marcher.

2
Nick Berardi

En moins d'un mois:

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

Ceci est une solution pour MS SQL Server: Elle renvoie les employés avec un anniversaire dans les 30 jours.

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

J'ai utilisé cela pour MySQL , probablement pas le moyen le plus efficace d'interroger mais assez simple à implémenter. 

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
Xocoatzin

Vous pouvez également utiliser 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))
0
Raj Sharma

Cette solution prend également en charge les anniversaires de l'année suivante et la commande: (Dob = jour de naissance; bty = anniversaire cette année; nbd = anniversaire suivant)

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

Cette version, qui évite la comparaison des dates, pourrait être plus rapide:

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

Si la plage couvre le 29 février de l'année suivante, utilisez:

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
Pilso

Solution simple et meilleure:

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
0
AjitChahal

sélectionnez Date de naissance, Nom des employés par cas QUAND convertir (nvarchar (5), Date de naissance, 101)> convertir (nvarchar (5), GETDATE (), 101), puis 2 WHEN convertir (nvarchar (5), BirthDate, 101) <convert (nvarchar (5), GETDATE (), 101) puis 3 WHEN convertir (nvarchar (5), BirthDate, 101) = convertir ( nvarchar (5), GETDATE (), 101) puis 1 autre 4 terminent, convertissent (nvarchar (2), date de naissance, 101), convertissent (nvarchar (2), date de naissance, 105)

0
hardik maheshwari

Anniversaire du mois en cours

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
Bhavesh Patel

Des noisettes! Une bonne solution entre le moment où j'ai commencé à y penser et le moment où je suis revenu pour y répondre. :)

Je suis venu avec:

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

Vous n'avez pas besoin de convertir getdate () en tant que date/heure, n'est-ce pas?

0
clweeks

Vous pouvez utiliser DATE_FORMAT pour extraire les parties jour et mois des dates de naissance.

EDIT: désolé, je n'ai pas vu qu'il n'utilisait pas MySQL.

0
p4bl0

Le meilleur moyen de réaliser la même chose est

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)
0
Ramandeep Singh

J'ai eu le même problème avec mon projet de collège il y a quelques années. J'ai répondu (d'une manière plutôt étrange) en scindant l'année et la date (MM: DD) en deux colonnes distinctes. Et avant cela, mon compagnon de projet obtenait simplement toutes les dates et les parcourait de manière programmée. Nous avons changé cela parce que c'était trop inefficace - non pas que ma solution soit plus élégante non plus. En outre, il est probablement impossible de le faire dans une base de données utilisée depuis un certain temps par plusieurs applications.

0
Mostlyharmless

Ceci est une combinaison de quelques réponses qui ont été testées. Cela trouvera le lendemain brithday après une certaine date et l'âge qu'ils seront. De plus, le nombre de jours limitera la plage que vous recherchez 7 jours = semaine, etc.

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
Kyle

je crois que ce billet a été fermé il y a bien longtemps, mais pour en savoir plus sur la requête SQL correcte, jetez un coup d'œil.

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

La requête ci-dessous renverra tous les prochains anniversaires d'employé, c'est la requête la plus courte.

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 ;

La requête ci-dessus couvrira tout le mois prochain, à l’exclusion de la date du jour.

0
Paresh Patel

En supposant qu'il s'agisse de T-SQL, utilisez DATEPART pour comparer le mois et la date séparément. 

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

Vous pouvez également soustraire le 1er janvier de l'année en cours à l'anniversaire de chacun, puis effectuer une comparaison en utilisant l'année 1900 (ou quelle que soit votre année d'époque).

0
Patrick Szalapski

La plupart de ces solutions sont proches, mais vous devez vous rappeler quelques scénarios supplémentaires. Lorsque vous travaillez avec des anniversaires et une échelle mobile, vous devez être capable de gérer la transition vers le mois prochain. 

Par exemple, l'exemple de Stephens convient parfaitement aux anniversaires jusqu'aux 4 derniers jours du mois. Ensuite, vous avez un défaut de logique car les dates valides si le 29 était aujourd’hui seraient: 29, 30, et ensuite 1, 2, 3 du mois suivant, vous devez donc vous aussi vous préparer.

Une alternative serait d’analyser la date à partir du champ Anniversaire et de l’année en cours, puis de faire une comparaison de plage standard.

0
Mitchel Sellers

Une autre pensée: Ajoutez leur âge en années entières à leur anniversaire (ou un autre si leur anniversaire n’a pas encore eu lieu, puis comparez comme vous le faites ci-dessus. Utilisez DATEPART et DATEADD pour le faire.

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

Le cas Edge d'une plage couvrant l'année devrait avoir un code spécial.

Conseil bonus: pensez à utiliser BETWEEN ... AND au lieu de répéter l’opérande Anniversaire.

0
Patrick Szalapski

Essayez ceci:

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)
0
Esteban Brenes

Cela devrait marcher ...

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
bastos.sergio

J'espère que cela vous aide d'une certaine façon ...

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

Anniversaire à venir pour l'employé - 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
samdoss