CASE statement with GETDATE() - sql

Wondering if you can help a little with the syntax here. Trying to set a variable as a month value dependent upon whether it is past the 25th day of the month.
If it is, then it uses the current month (e.g. the variable 'month' will be 10 if the date is 28th October, but will be 9 if it's the 24th October). So far I've got the following:
select a
case
when (SELECT DAY(GETDATE()) >= 25
then a = (SELECT MONTH(GETDATE()))
else a = (SELECT MONTH(GETDATE()) - 1)
end
I understand you can't use less than or greater than signs, as case statements are only for evaluations (=)? Can anyone suggest another way of doing this?
Thanks.

select #your_variable = case when DAY(GETDATE()) = 25
then MONTH(GETDATE())
else MONTH(GETDATE()) - 1
end

As far as I understand, you need this kind of usage;
select
case
when DAY (GETDATE()) = 25 then MONTH(GETDATE())
else MONTH(GETDATE()) - 1
end

You can use > and < operators with CASE. Is the following what you expected?
SELECT CASE WHEN DAY(GETDATE()) > 24
THEN MONTH(GETDATE())
ELSE MONTH(GETDATE()) + 1
END AS [a]

IF
DAY(GETDATE()) <=25
SELECT DATEADD(month,-1,CURRENT_TIMESTAMP)

Related

Calculating age in where clause

In the users table I have birth_date column. I want to select only users under the age 18.
I tried using alias
select
*,
age = case
when datediff(year, getdate(), birth_date) > 0
then year(getdate()) - year(birth_date) - 1
else year(getdate()) - year(birth_date)
end
from
users
where
age < 18
But apparently I cannot use alias in where.
So I tried using case but it's also not gonna work
select *
from users
where
case
when datediff(year, getdate(), birth_date) > 0
then year(getdate()) - year(birth_date) - 1 < 18
else year(getdate()) - year(birth_date) < 18
What shall I do in this case? I don't want to use a stored procedure.
Use cte
WITH cte AS
(
SELECT *,
CASE
WHEN DATEDIFF(year, getdate(), birth_date) > 0
THEN year(getdate()) - year(birth_date) - 1
ELSE year(getdate()) - year(birth_date)
END AS age
FROM users
)
SELECT *
FROM cte
WHERE age < 18
demo in db<>fiddle
The correct way to do this is not to use DATEDIFF at all. It will be less accurate (as it uses date boundaries) and slower (it can't use indexes).
Instead use DATEADD against the current date, do not use functions against the column
SELECT *
FROM dbo.users
WHERE birth_date > DATEADD(year, -18, GETUTCDATE()) -- maybe cast right-side to DATE?
db<>fiddle
simple use this !
SELECT * FROM dbo.users WHERE DATEDIFF(day,birth_date,GETDATE()) < 6570
I think you're just looking for direction on how to use an alias/CASE statement in a column?
If that's correct, then you'll just need to surround your alias with brackets.
select *
,case
when datediff(year, getdate(), birth_date) > 0
then year(getdate()) - year(birth_date) - 1
else year(getdate()) - year(birth_date)
end as age
from users
where age < 18
Below is one way to calculate age which accounts for leap days and other complexities. This calculates the difference of the yyyymmdd integer values and then divides by 10000 to evaluate only the year difference.
SELECT *
FROM users
WHERE
(CAST(FORMAT(GETDATE(), 'yyyyMMdd') AS int) -
CAST(FORMAT(birth_date, 'yyyyMMdd') AS int)) / 10000 < 18;

Fiscal Year from Current Date

I'm using SSMS/SSRS2012 working on report to capture all hours worked in the current fiscal year, which for this purpose is Oct 1-Sep 30.
I'm looking for a case statement that says the following:
if the current month < 10 (october) then #FYStart = last year
if the current month >= 10 then #FYStart = current year
When I query SELECT GETDATE() here is the format: 2020-06-16 15:24:57.637
I have tried the following, but it only half works.
SELECT CASE WHEN DATEPART(MONTH,(CAST(getdate() AS INT)))>09
THEN YEAR(CAST(getdate() AS INT))
ELSE DATEADD(YEAR,-1,(CAST(getdate() AS INT)))
END
The result from this gives me 2019-06-17 00:00:00.000 which is a step in the right direction, but if I change the month to a month that has already passed,
SELECT CASE WHEN DATEPART(MONTH,(CAST(getdate() AS INT)))>03
THEN YEAR(CAST(getdate() AS INT))
ELSE DATEADD(YEAR,-1,(CAST(getdate() AS INT)))
END
I get this result: 1905-07-14 00:00:00.000
Something is obviously going wrong here but I'm not sure what exactly. I'm thinking it's something with the data types but I'm not sure what to check/where to start.
So from what I gather, you are trying to isolate the year (as an integer) from today's date and store it in #FYStart. If today's date is before October, you want to assign it to last year, and if it's October or later, assign it to this year, correct?
If so, try this:
DECLARE #FYStart int
SET #FYStart = (
SELECT CASE WHEN DATEPART(MONTH, GETDATE()) < 10
THEN DATEPART(YEAR, DATEADD(YEAR, -1, GETDATE())) -- last year
ELSE DATEPART(YEAR, GETDATE()) -- this year
END
)
Unless I'm overlooking something, is it not just something as simple as...
SELECT CASE WHEN MONTH(getdate()) <10
THEN YEAR(getdate()) -1
ELSE YEAR(getdate())
END

SQL Server DATEDIFF round up the YEAR difference. How to round it down?

I have a problem that I tried googling but most questions are about rounding down hours or minutes.
I'm checking birthday dates for users and I have two dates that are 99.3 years apart. That means that the user is 99 years old but this piece of code:
DATEDIFF(YEAR, r.BirthDate, ISNULL(#Date,GETDATE()))
returns a value of 100. Is there a way to round the value down?
You can use this logic to get the correct age:
select (case when month(birthdate) * 100 + day(birthdate) >=
month(getdate()) * 100 + day(getdate())
then year(getdate()) - year(birthdate)
else year(getdate()) - year(birthdate) - 1
end) as age
This should be accurate, even in the presence of leap years. Basically it looks at the month-day portion of the birthdate and checks if it is on or later than today. The logic uses this information to determine the age in year.
fin the difference in whole years (year - birth year) This is always the age the person reaches in that year. Knock a year off if it is earlier than their birthday.
Never be tempted to use day difference divided by 365.25 or 365 - for all sorts of reasons, the age can end up coming out wrong at certain dates, sometimes around leap-years
SELECT YEAR(getdate()) - YEAR(birthdate)
- CASE WHEN MONTH(getdate()) < MONTH(birthdate)
OR (DAY(getdate()) < DAY(birthdate) AND MONTH(getdate()) = MONTH(birthdate) )
THEN
1
ELSE
0
END
This is how fixed it.
Instead of:
DATEDIFF(YEAR, r.BirthDate, ISNULL(#Date,GETDATE()))
use this:
FLOOR(DATEDIFF(week, r.BirthDate, ISNULL(#Date,GETDATE())) / 52.177457)
Here's an article that demonstrates that this trick works like a charm.
You can use the following solution using MONTH instead of YEAR:
DECLARE #currdate AS DATE = '2019-02-08'
-- using YEAR
SELECT DATEDIFF(YEAR, '2000-05-01', ISNULL(#currdate, GETDATE())) -- 19
-- using MONTH
SELECT DATEDIFF(MONTH, '2000-05-01', ISNULL(#currdate, GETDATE())) / 12 -- 18
You can also ROUND up and down:
DECLARE #date DATE = '2019-02-08'
SELECT CAST(ROUND(DATEDIFF(MONTH, '1999-08-01', ISNULL(#date, GETDATE())) / 12.0, 0) AS INT)
-- 20 (19.5)
SELECT CAST(ROUND(DATEDIFF(MONTH, '1999-09-01', ISNULL(#date, GETDATE())) / 12.0, 0) AS INT)
-- 19 (19.4)
is there a way to round down days?
You can use days to round for days but this isn't more precise in some cases. You can check if the current date passed the day of birth or not (as #Cato mentioned in comments). In case the day of birth is greater than the current day (in same month) you can subtract a month.
DECLARE #birthday AS DATE = '2000-10-25'
DECLARE #currdate AS DATE = '2100-10-24'
SELECT ((DATEDIFF(MONTH, #birthday, ISNULL(#currdate, GETDATE())) - (CASE WHEN MONTH(#birthday) = MONTH(#currdate) AND DAY(#birthday) > DAY(#currdate) THEN 1 ELSE 0 END)) / 12)
-- 99
The accepted solution by Gordon is good but the logic is reversed? The general idea is to see if the current month + day is greater than the birthdate's month + day and, if not, then subtract a year from the difference in years, because it hasn't reached or surpassed their birthdate yet.
SELECT YEAR(GETDATE()) - YEAR(birthdate)
- IIF(MONTH(GETDATE()) * 100 + DAY(GETDATE()) >= MONTH(birthdate) * 100 + DAY(birthdate), 0, 1)
Another way to solve this (without calculating the date difference 3 times or more) is to get the total number of years when subtracting the two values:
SELECT datediff(YEAR, '1900', DATEADD(d, -1, GETDATE()) - r.BirthDate)
we subtract 1 day from the current date as the other day is '1/1/1900', which adds one day to the interval.
In Snowflake:
ROUND(DATEDIFF('month', "dateOfBirth", CURRENT_DATE())/12)
You have to do it by months as if you pick years it seems to round up.

Current Year To Date, Last Year To Date, and Other

I need to classify a set of dates as either 'Cur. YTD', 'Lst. YTD', or 'Other'. YTD is based upon getdate(). I have a temp table for testing that has a single column called 'calendar_date' of type DATETIME. I came up with this logic and it appears to work. I'm just wondering if this approach makes good sense from a performance perspective or if something else might be better.
select calendar_date,
case when (MONTH(calendar_date) < MONTH(getdate()))
or (MONTH(calendar_date) = MONTH (getdate())
AND DAY(calendar_date) <= DAY(getdate())) then
case when YEAR(calendar_date) = YEAR(GETDATE()) then 'CYTD'
when YEAR(calendar_date) = YEAR(getdate()) - 1 then 'LYTD'
else 'Other'
end
else 'Other'
end as Tim_Tag_YTD
from #temp1
Your logic looks good and will work as-is.
An alternative which simplifies a little, which assumes you have no future data.
select
calendar_date,
Tim_Tag_YTD = case DATEDIFF(YEAR, calendar_date, GETDATE())
when 0 then 'CYTD'
when 1 then 'LYTD'
else 'Other'
end
from #temp1;
In the case of your logic, you are explicitly putting future data into 'Other', which you can also do like this:
select
calendar_date,
Tim_Tag_YTD = case when calendar_date > GETDATE() then 'Other' else
case DATEDIFF(YEAR, calendar_date, GETDATE())
when 0 then 'CYTD'
when 1 then 'LYTD'
else 'Other'
end
end
from #temp1;
Sometimes something unintuitive performs faster. Something like this might be worth a shot.
set variable #FirstOfLastYear to Jan 1 of last year
using sql server date functions
set #FirstOfThisYear = DateAdd(year, 1, #FirstOfLastYear)
select 'last year' period
, whatever else you need
from #temp1 where calendar_date >= #FirstOfLastYear
and calendar_date < #FirstOfThisYear
union
select 'this year' period
, whatever else you need
from #temp1 where calendar_date >= #FirstOfThisYear
and calendar_date < getDate ()
union
select 'other' period
, whatever else you need
from #temp1 where calendar_date <= #FirstOfLastYear
or calendar_date > getdate()
You'll never know unless you try.

SSRS - How to group Date into Today/Yesterday/Week/Month in a Matrix?

I have data sorted by dates:
e.g.
Region - Date - Count
East - 2012/01/01 - 5
West - 2012/01/01 - 2
East - 2012/01/06 - 3
South - 2012/01/07 - 3
etc
I'm trying to create a sum of the Counts, grouped by date groups relative to today. So for example
Assuming today was 2012/01/07:
Yesterday is defined to be from Today - 1 to today (non-inclusive of
today)
Week is defined to be from Today - 7 to today (non-inclusive of
today)
Month is defined to be from Today - 28 to today (non-inclusive
of today)
The output in the matrix for the sample data would be:
As a bonus, ideally I'd have a 5th column that's for "On Demand" Start and End date range for the user to input.
I think the key is to add an EXPR in the Column Group's Group On property but I don't know what the Expression should be.
Any help would be great!
Personally I think I would prefer to attack it in the SQL query. So for example
SELECT
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) = 0 THEN SomeColumn ELSE 0 END cToday
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) = 1 THEN SomeColumn ELSE 0 END cYesterday
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) > 0 AND
DATEDIFF(day, GETDATE(), DateColumn) < 8 THEN SomeColumn ELSE 0 END cWeek
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) > 0 THEN SomeColumn ELSE 0 END cMonth
FROM
SomeTable
WHERE
DateColumn > DATEADD(day, -28, GETDATE())
Otherwise you could use a similar approach inside SSRS