Comparing dates in Transact-SQL - sql

Why does comparison works weird in this example?
Dates, which are birthdays, are:
1990-03-22
1998-03-20
1990-03-22
2002-12-02
2004-03-18
2004-03-20
2004-03-25
I'm doing this
WHERE DATEADD(YY, 18, jun.birth_date) >= DATEADD(YY, 1, GETDATE())
Which, I think, should cut off all the entries of people older than 18 in a year from today. But it does absolutely opposite, here's what I get:
2004-03-18
2004-03-20
2004-03-25
And I get right results when I seacrh for entries less and even than date in the next year.
Why does it work like this?

This is what your have...
WHERE
someone's date of birth + 18 years
>=
Today's date + 1 year
In English, thats; where the 18th birthday is a year or more in the future.
I think what you really want (if you want people who are 18 or older) is... WHERE the birthdate is earlier than today's date minus 18 years (18 or more years ago)
WHERE
Jun.birth_date <= DATEADD(YY, -18, GETDATE())

If you want people who are 18, or older today, then take 18 years off today, don't add years to the DoB column, as that makes the query non-SARGable:
SELECT birth_date
FROM dbo.YourTable
WHERE birth_date <= DATEADD(YEAR, -18, CONVERT(date,GETDATE()));

Why don't you use datediff, instead of dateadd?
with d as (
select cast('1990-03-22' as date) as birthDate union all
select cast('1998-03-20' as date) as birthDate union all
select cast('1990-03-22' as date) as birthDate union all
select cast('2002-12-02' as date) as birthDate union all
select cast('2004-03-18' as date) as birthDate union all
select cast('2004-03-20' as date) as birthDate union all
select cast('2004-03-25' as date) as birthDate
)
select *
from d
where datediff(year,birthDate, getdate()) >= 18
It's easier to understand the behaviour.

Related

Get employee with tenure of 2 to 5 years in sql

I have a tenure table where I have columns link id, name, join date of an employee.
I am trying to get only those employee whose tenure(work experience) is 2 to 5 years from join date to today's date.
I used query
SELECT ID FROM tenure WHERE DATEADD(year, 2, JoinDate) >= '2018-08-06' AND DATEADD(year, 5, JoinDate) <= '2018-08-06';
My tabular structure is
How can I get only those employees whose working period or tenure is between 2 to 5 years from their join date to today's date?
You can use TimeStampDiff() :
SELECT ID
FROM tenure t
WHERE timestampdiff(YEAR, JoinDate, now()) >= 2 AND
timestampdiff(YEAR, JoinDate, now()) <= 5;
use TIMESTAMPDIFF function
SELECT ID FROM tenure WHERE
TIMESTAMPDIFF(YEAR, date(joindate), date(now()))>= 2 and
TIMESTAMPDIFF(YEAR, date(joindate), date(now()))<=5
To me, your syntax suggests SQL Server. The logic would be:
where joindate >= dateadd(year, -5, getdate()) and
joindate < dateadd(year, -2, getdate())
Compare the Joindate to the expected range based on today's date
select *
from tenure
where joindate between DATE_ADD(cur_date(), INTERVAL -5 YEAR)
and DATE_ADD(cur_date(), INTERVAL -2 YEAR)

SQL Server 3 month from now

I need a SQL select statement to retrieve all employees that their enddate contract will end three month from now and only three month not more or less
It depends what you mean by 3 months from now. If you mean on that exact date, then:
WHERE my_date_column = cast(dateadd(month, 3, getdate()) as date)
Note the cast to date to remove the time component. This is ambiguous and under some circumstances might miss employees or count them twice.
If you want employees whose contract ends in the 3rd month from today, then use:
WHERE DATEDIFF(month, getdate(), my_date_column) = 3
So, if this is January, this will return employees whose contract ends any time in April.
SELECT *
FROM TABLE_NAME
WHERE Date_Column >= DATEADD(DAY, +90, GETDATE())
OR
SELECT *
FROM TABLE_NAME
WHERE Date_Column >= DATEADD(MONTH, +3, GETDATE())
OR
SELECT *
FROM TABLE_NAME
WHERE DATEDIFF(MONTH, my_date_column, GETDATE()) <= 3

SQL Select query using current date time to get the users ages? [duplicate]

This question already has answers here:
How to calculate age (in years) based on Date of Birth and getDate()
(40 answers)
Closed 7 years ago.
I want to find age, for example, between 20 to 30 from my table from the current system date.
Below is my table details:
GivenName DOB
Raj 1950-06-06 00:00:00.000
Rahul 1951-01-06 00:00:00.000
Mohan 1952-11-09 00:00:00.000
khan 1953-07-24 00:00:00.000
for example, between 20 to 30
Use DATEDIFF:
SELECT Age = DATEDIFF(year, DOB, GetDate()),
Between20_30 = CASE WHEN DATEDIFF(year, DOB, GetDate()) BETWEEN 20 AND 30
Then 'yes' ELSE 'no' END
FROM dbo.Table1
Demo
If you want to filter by persons who are between 20 and 30 use a WHERE clause:
WHERE DATEDIFF(year, DOB, GetDate()) BETWEEN 20 AND 30
Since DATEDIFF ist not precise(treats the month difference between 12/31 and 01/01 as one month), if that's an issue you could use this approach.
select GivenName,Age = DATEDIFF(year, DOB, GetDate())
FROM [dbo].[AgeCalc] where DATEDIFF(year, DOB, GetDate()) BETWEEN 20 AND 30
Don't use DATEDIFF. When using DATEDIFF(year, ...) it is only the year part of the dates that is being considered. So it wouldn't matter which birthday exactly and you'd consider people 20 years old who are not yet full twenty years old.
Today 2015-12-26 you would want persons born between 1984-12-17 till 1995-12-16.
1984-12-17 (today minus 31 years plus one day) means the person gets 31 tomorrow
1995-12-16 (today minus 20 years) means the person just got 20 today.
So:
select *
from persons
where convert(varchar, dob, 102)
between convert(varchar, dateadd(day, 1, dateadd(year, -31, getdate())), 102)
and convert(varchar, dateadd(year, -20, getdate()), 102);
(I must admit though that I am too lazy to think the February 29 thing through now.)

select month and year from Date of birth IN sql

i have table with DOB column ('2012-05-29 00:00:00.000') and few other fields , i need to select the data for DOB between 6 months to 6 Years. I tried using the below SQL but this is not giving me the right data. any help will be appreciated.
select * from dbo.xyz
where ( FLOOR(DATEDIFF(MONTH, birth_date , GETDATE()) % 12) >=6
AND FLOOR(DATEDIFF(DAY, birth_date , GETDATE()) / 365.25) <= 6
)
When using dates, the advice is to use functions only on the non-column values. In other words, modify getdate(), not birth_date:
select *
from dbo.xyz
where birth_date between dateadd(year, -6, getdate()) and dateadd(month, -6, getdate())
This has two advantages. First, it makes the where clause "sargable", which means an index can be used on the comparison. More importantly, the alternative of using datediff() doesn't quite work as expected. datediff() counts the number of calendar boundaries between two values. So, 2014-12-31 and 2015-01-01 are one day apart, one month apart, and even one year apart.
Try this
select * from dbo.xyz
where DATEDIFF(MONTH, birth_date , GETDATE()) between 6 and 72
Here is another option that will allow indexing on birthdate.
select *
from dbo.xyz
where birthdate > DATEADD(YEAR, -6, GETDATE())
and birthdate < DATEADD(MONTH, -6, GETDATE())

How to group daily data on weekly basis using sql

I am trying to group the number of hours that employees worked for the last 4 weeks but I want to group them on a weekly basis. For example:
WEEK HOURS
Feb 24 to March 2 55
March 3 to March 9 40
March 10 to March 16 48
March 17 to March 23 37
This is what I have so far, please help. thanks
SET DATEFIRST 1
SELECT CAST(MIN( [DT]) AS VARCHAR(20))+' TO '+CAST (MAX([DT]) AS VARCHAR(20)) AS DATE,
SUM(HOURS) AS NUM_HRS
FROM MyTable
GROUP BY DATEPART(WEEK,[DT])
HAVING COUNT(DISTINCT[DT])=7
Create a Calendar auxilliary table, with Year, Month, Week, Date columns (you can also add holidays and other interesting stuff to it, it has many potential uses) and populate it for the period of interest.
After that, it's as easy as this:
SELECT sum(hours), cast(min(date) as varchar), cast(max(date) as varchar)
FROM Calendar c
LEFT OUTER JOIN MyTable h on h.Date = c.date
GROUP BY year, week
ORDER BY year, week
SET DATEFIRST 1
SELECT DATEPART(WEEK,DT) AS WEEK,
SUM(HOURS) AS NUM_HRS
FROM MyTable
WHERE DT >= DATEADD(WEEK, -4, GetDate()),
GROUP BY DATEPART(WEEK,[DT])
Try something like
SELECT
DATEADD(DD,
CONVERT(INT, (DATEDIFF(DD, '1/1/1900', t.DT)/7)) * 7,
'1/1/1900') [WeekBeginDate],
DATEADD(DD,
(CONVERT(INT, (DATEDIFF(DD, '1/1/1900', t.DT)/7)) * 7) + 6,
'1/1/1900') [WeekEndDate],
SUM(HOURS) AS NUM_HRS
FROM MyTable t
GROUP BY CONVERT(INT, DATEDIFF(DD, '1/1/1900', t.DT)/7)
Though this is the brute force trick, I think in your case it will work.
EDIT : Modified the query a little bit, the error was caused because of the order in which DATEDIFF calculates the difference.
Also here is a SQL FIDDLE with a working example.
EDIT 2 : Updated the Fiddle with the Date Format. To customize the date format, this article would help.