Sorry for the misunderstanding.. let me try to clear this up
I'll keep this short and thanks for the help!
I have an age case I want to return the number of days between current date and the import date here is my original query I am wanting to change.
Thanks again
age = case
when datediff(day, ( t.importdate), getdate()) > 365 then J - 366+
when datediff(day, ( t.importdate), getdate()) > 270 then I - 271 to 365
when datediff(day, ( t.importdate), getdate()) > 240 then H - 241 to 270
This query will group the datediff and it goes all the way down to A before it ends, this is meant just show the person the categories the datediff would fall into.
What I want to accomplish is getting rid of the grouping function but still run a case that will return the datediff to just numbers...
ex.. instead of > 365 then J - 366+ It would just return say 18, which would be the days in between that specific instance..I am running hundreds of user accounts all with different import dates I want to compare with current date..
I hope this is clear!
I suspect that you are looking to return ages in groups. If so, this may be what you are looking for:
select age = (case when datediff(day, t.importdate, getdate()) > 365
then 'J - 366+'
when datediff(day, t.importdate, getdate()) > 270
then 'I - 271 to 365'
when datediff(day, t.importdate, getdate()) > 240
then 'H - 241 to 270'
else 'G - <270
end)
Related
I'm trying to tally up the number of unique ID accounts that are active for more than a year as well as include how long each one is active. The problem with the code I have is it's not including accounts that are currently active (ones that don't have an end date). For example, if the begin date was May 01 2018 but has no end date since it's currently active, it should also be included in this query. Here's what I have so far..
SELECT UniqueID,
DATEDIFF(yy, Begin_Date,End_Date) as timeactive
FROM TABLE
WHERE DATEDIFF(yy, Begin_Date,End_Date) > 1
I want my output to look like...
Unique ID Time active
F000012 2.5
F000031 1.5
This is what ended up working:
SELECT UniqueID,
CAST(ROUND(DATEDIFF(day, Begin_Date, COALESCE(End_Date, getdate()))/365.0, 1, 0) AS NUMERIC (10,1)) as timeactive
FROM TABLE
WHERE DATEDIFF(day, Begin_Date, COALESCE (End_Date, getdate())) >= 365
If the EndDate is null then the output of the DateDiff function will be null, and any null compared to anything (even another null) is a result of null (usually then interpreted as false)
I suggest you use COALESCE to convert your end date to today if it is null:
SELECT
UniqueID,
DATEDIFF(yy, Begin_Date,COALESCE(End_Date, GetUtcDate()) as timeactive
FROM TABLE
WHERE DATEDIFF(yy, Begin_Date,COALESCE(End_Date, GetUtcDate()) > 1
You should bear in mind that the DATEDIFF function as used here, in SQLserver does NOT return the amount of time that has passed between the two dates. It returns the number of times the named interval has changed between the two dates
For example, DATEDIFF(year, 2000-01-01, 2000-12-31 23:59:59) will return 0 because these are both year 2000 even though they're just one second short of being a year apart. If you do DATEDIFF(year, 2000-12-31 23:59:59, 2001-01-01 00:00:01) even though these dates are only two seconds apart datediff will report them as 1 year apart because the year number has changed from 2000 to 2001.
DATEDIFF counts up by one every time the clock rolls past an interval change and in this case the interval is Year
To get your dates to report as 1.5 years etc you should consider to datediff by a smaller interval and divide, such as asking for the DAYS diff between two dates and then dividing by 365.25- the average number of days in a year. The smaller the interval you ask datediff for the more accurate the result will be but it'll never be 100%. If you're only after results to one decimal place of a year then days will be accurate enough
To get 1 decimal place, cast to a numeric with 1 DP:
SELECT
UniqueID,
CAST(DATEDIFF(day, Begin_Date,COALESCE(End_Date, GetUtcDate())/365.25 AS NUMERIC(5,1)) as timeactive
FROM TABLE
WHERE DATEDIFF(day, Begin_Date,COALESCE(End_Date, GetUtcDate()) >= 365
If you want time active as fractional years, then you need to use a smaller unit of time and divide. For instance:
SELECT UniqueID,
DATEDIFF(month, Begin_Date, COALESCE(End_Date, GETDATE())) / 12.0 as timeactive
FROM TABLE
WHERE Begin_Date < DATEADD(YEAR, -1, COALESCE(End_Date, GETDATE()))
Note the change in the WHERE clause. DATEDIFF() counts the number of year boundaries between dates. So the difference in years between 2019-01-01 and 2020-12-31 is the same as the difference between 2019-12-31 and 2020-01-01 -- exactly 1.
Consider:
SELECT
UniqueID,
DATEDIFF(yy, Begin_Date, COALESCE(End_Date, getdate()) as timeactive
FROM TABLE
WHERE DATEDIFF(yy, Begin_Date, COALESCE(End_Date, getdate()) > 1
This works by using the current date as default value for empty End_Dates. So this allows records with empty end date if their start date is more than one year ago.
WHERE
StartDate BETWEEN
CAST(FLOOR(CAST(DATEADD("month", - 12, ISNULL(RunDate.testdate, GETDATE()) - DAY(ISNULL(RunDate.testdate, GETDATE())) + 1) AS FLOAT)) AS DATETIME)
AND
CAST(FLOOR(CAST(ISNULL(RunDate.testdate, GETDATE()) - DAY(ISNULL(RunDate.testdate, GETDATE())) + 1 AS FLOAT)) AS DATETIME)
/*************************************************
SQL Server 2005 (9.0 SP4)
StartDate is of TYPE DATETIME
StartDate date looks like 2012-07-05 12:45:10.227
RunDate is a TABLE with no records
RunDate.testdate is always NULL
**************************************************/
This WHERE clause works and produces the expected results for what the business expects
but seems excessively untidy.
All that this is attempting to achieve is to bring across all records for the last 12 months, when run in July of any year. So records from 1 July 2013 to 30 June 2014.
Here is another expression:
where startdate > cast(dateadd(year, -1, getdate() - day(getdate()) as date) and
startdate <= cast(getdate() - day(getdate()) as date)
When you subtract a number from a datetime it is treated as a number of day, which can be easier to read.
EDIT:
Oh, that's 2005, not 2008. The date logic goes like this . . . :
where startdate > cast(dateadd(year, -1, dateadd(day, - day(getdate()), getdate()) as date) and
startdate <= cast(dateadd(day, - day(getdate()), getdate())
But you will have times on the date. There actually isn't an easy way to convert this to a date. You can do this more readily with a subquery:
from (select dateadd(day, 0, datediff(day, 0, getdate())) as today) const
where startdate > dateadd(year, -1, dateadd(day, - day(today), today) and
startdate <= cast(dateadd(day, - day(today), today)
If you abandon the x BETWEEN a AND b pattern in favour of one that could roughly be expressed as
x BEGINS WITH a
ENDS BEFORE b
(which, of course, is not valid SQL syntax but x >= a AND x < b would be a decent replacement), you will end up with both a and b having same granularity (specifically, months, because each of the two points would be the beginning of a month).
In this case it is very opportune because it will allow you to factorise calculation of both a and b nicely. But before I get there, let me tell (or remind) you about this date/time truncation technique in SQL Server:
DATEADD(unit, DATEDIFF(unit, SomeFixedDate, YourDateTime), SomeFixedDate)
In your case, the unit would be MONTH. As for SomeFixedDate, there is an established practice of using 0 there for brevity, 0 representing the date of 1900-01-011.
So, using this technique, the beginning of the current month would be calculated as
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
That would be the end of your interval. The beginning of the interval would be same except you would subtract 12 from the DATEDIFF's result, and so the complete condition to match the range would look like this:
WHERE StartDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 12, 0)
AND StartDate < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
If that still looks a mouthful to you, you could try getting rid of the repetition of DATEDIFF(MONTH, 0, GETDATE()). You could view it as some abstract month number and reference it as such in both DATEADD calls. The CROSS APPLY syntax would help you with that:
…
CROSS APPLY (
SELECT DATEDIFF(MONTH, 0, GETDATE())
) AS x (MonthNo)
WHERE StartDate >= DATEADD(MONTH, x.MonthNo-12, 0)
AND StartDate < DATEADD(MONTH, x.MonthNo , 0)
Yes, that seems factorised all right. However, it might not lend itself well to readability. Someone (even yourself, at some later point) might look at it and say: "Huh, MonthNo? What in the world is that? Ah, that number…" If I were to factorise your interval calculation, I might consider this instead:
…
CROSS APPLY (
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
) AS x (ThisMonth)
WHERE StartDate >= DATEADD(YEAR, -1, x.ThisMonth)
AND StartDate < x.ThisMonth
I admit, though, that readability is not a perfectly objective criterion and sometimes one chooses to write one way or the other based on one's personal tastes/preferences.
1Although hard-coding a date as an integer value is not a normal practice, I would argue that this truncation technique is a special case where using 0 in place of a datetime value should be okay: that usage appears to be so widespread that it may by now have become a "fixed expression" among those using it and is, therefore, unlikely to cause much confusion.
My first question would be: what do you expect to see if someone executes this at any time other than July?
Never assume something outside your control. You have no control over when this will be executed so write it so it will always execute during the correct time period no matter what.
Because there are a number of ways to do this based on DBMS and even version of DBMS (SS 2005 vs 2008, for example) here it is in human-speak:
-- Get the difference, in years, between sysdate and the base date
-- Add that to the base date. You now have Jan 1 of whatever year it is.
-- Add 6 months. You now have Jul 1 of that year.
-- Add 1 year and subtract 1 day. You now have Jun 30 of the following year.
Your query will now operate on the correct range no matter when it is executed. Of course, if it is executed in, say, February, the results will not be complete because some of the range will be in the future. But the results will always be correct for the time it is executed.
One adjustment you could make is that, if executed before Jul 1 of any year, it generates a range for the most recent complete year. So Jul 1 2012 to Jun 30 2013 if executed anytime before Jul 1 2014.
[Edit: I suppose since I brought it up, I should specify how that could be done. In the first step above, where it says sysdate, change it to (sysdate minus 6 months).]
It really doesn't matter which way you design it, as long as your users know what to expect. But whatever you do, don't let your query depend on users' ability to execute it at the right time.
In SQL Server 2005, you can use DATEADD and DATEDIFF to remove the time component and compute exact month boundaries:
WHERE
startdate >= DATEADD(year, -1, DATEADD(month, DATEDIFF(month, '', GETDATE()), ''))
AND startdate > DATEADD(month, DATEDIFF(month, '', GETDATE()), '')
My current query is
case when datediff(day, isnull(installment_duedate, due_date), getdate()) < 30
then amount_due else 0 end as [unpaid under 30 days]
I have another 3 case that does between 30-60 days, between 60-90s and greater then 90 days.
My current problem is, my installment_duedate has future dates in it. If someone has an installment due date it would be something like 12-02-2012, 03-02-2013, 06-02-2013, 09-02-2013. If it's in the future I would like it to return as 0 for now but currently the amount is showing up in my under 30 days.
Any pointers would be greatly appreciated!
You need to change your case to:
CASE WHEN DATEDIFF(DAY, ISNULL(installment_duedate, due_date), GETDATE()) BETWEEN 0 AND 30
THEN amount_due ELSE 0 END AS [unpaid under 30 days]
In this line , when installment_duedate is past date , DATEDIFF returns negative value which is less than 30 and hence < 30 condition gets satisfied
datediff(day, isnull(installment_duedate, due_date), getdate()) < 30
Format
DATEDIFF(datepart,startdate,enddate)
for solution to it , see Lamak's answer below
i want to make a select, where the users birthday(date field) is less than 30 days.
what is the best way to to do it? i tried datediff, but i don't know how to put the year aside.
Thanks
You could just use DATEPART function with dayofyear datepart value.
EDIT: honestly, there is a boundary issue in my previous answer (many thanks to Damien): e.g. 2010-12-25 and 2011-01-07 => the difference should be less then 30 days, but DATEPART(dayofyear, #date) - DATEPART(dayofyear, [Birthday]) < 30 condition would skip this record. So I added an additional contition to my answer:
DATEPART(dy, #d) - DATEPART(dy, [Birthday]) < 30 OR
(
DATEPART(mm, #d) = 12 AND
DATEPART(dy, DATEADD(m, 1, #d)) - DATEPART(dy, DATEADD(m, 1, [Birthday])) < 30
)
it adds one month to the each date in the case when the month part of the first date is December and compares the difference.
A common way is to compose a formatted date, as text, and replace the year with the current year; and parse back into a date. Apply datediff on that.
If you find out datediff returns something negative thus the birthday of this year is in the past, add 1 year, and try again. This is for the time period around New Year.
SELECT *
FROM dbo.CheckBirthDay
WHERE (CASE WHEN YEAR(BirthDay) <= YEAR(CURRENT_TIMESTAMP) THEN DATEDIFF(DD,BirthDay,CURRENT_TIMESTAMP) END < 30 )
I have a column in my sql server 2005 table that should hold the number of months an employee has been in service.
Since I also have the date the employee was engaged, I want the "months_In_Service" column to be a computed column.
Now if I use DATEDIFF(month,[DateEngaged],GETDATE()) as the formula for the months in service computed column, the results are correct some times and other times incorrect.
What would be the better reliable way to get the number of months between the DateEngaged value and the current date? Which formula should i use in my computed column?
Something like (might need to swap the 1 and 0, untested)
datediff(month,[DateEngaged],getdate()) +
CASE WHEN DATEPART(day, [DateEngaged]) < DATEPART(day, getdate()) THEN 1 ELSE 0 END
DATEDIFF measure month boundaries eg 00:00 time on 1st of each month, not day-of-month anniversaries
Edit: after seeing OP's comment, you have to subtract 1 if the start day > end day
DATEDIFF (month, DateEngaged, getdate()) -
CASE
WHEN DATEPART(day, DateEngaged) > DATEPART(day, getdate()) THEN 1 ELSE 0
END
So for 20 Dec to 13 Jan, DATEDIFF gives 1 and then 20 > 13 so subtract 1 = zero months.
Same approach as gbn, but with less keystrokes :-)
SELECT
DATEDIFF(MONTH, DateEngaged, GETDATE()) +
CASE
WHEN DAY(DateEngaged) < DAY(GETDATE())
THEN 1
ELSE 0
END
Maybe you want something like:
(year(getdate())-year([DateEngaged]))*12+(month(getdate())-month([DateEngaged]))
If You presume that month is meaning for 30 days You can also round vale
round((datediff(day,[DateEngaged],getdate()))/30.00,0)