Fiscal Year from Current Date - sql

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

Related

What is -1 and 0 doing in date add function?

dateadd(mm, DATEPART(MONTH, DATE) - 1, 0) + DATEPART(DAY, DATE) - 1
OUTPUT date is in the year for example 1990-12-02 00:00:00:000
Full query is below:
SELECT dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0) + dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0) + DATEPART(DAY, GP_DATE) - 1 GP_DATE
from table
I am trying to convert this query into snowflake syntax and snowflake syntax dateadd function does not allow 1, 0.
In SQL Server, there are some rather ugly implicit conversions available between datetimes and integers.
0, when converted to a date, becomes 1900-01-01.
You're also allowed to do maths on dates. Adding or subtracting 1 adds or subtracts 1 day from the date. Putting these facts together, we have:
dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0)
Which is taking the current year, and subtracting 1900 from it (or 1899 if the month is less than 11, for whatever reason). We then take that number and add it back to the date 0 (which as stated above is 1900-01-01). The result is that we get the first of January of next year or this year, depending on the month of GP_DATE. Call this D1.
Moving on:
dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0)
is taking the month of GP_DATE, subtracting 1 from it and adding that number of months to the date 0 (1900-01-01). The result is a the 1st of whichever month GP_DATE is in, but in 1900. Let's call this D2.
When we add D1 and D2 together, we approximately get a date of the 1st of whichever month GP_DATE is in, in either this year or next year. Note, however, that this goes wrong if the D1 year is a leap year, we get it wrong by a day for months after February.
Finally, we take DATEPART(DAY, GP_DATE) - 1, where we take the day of the month from GP_DATE, subtract 1, and add that on to our result so far. This should set the final date to be on the same day of the month as GP_DATE, except for the error mentioned above.
So, it appears that the code is trying to take GP_DATE and get the same date in either this year or next year, depending on how late in the year GP_DATE is. However, it also appears it was never tested with consideration for leap years.
A far more likely correct version of this query would be this instead:
SELECT
DATEADD(year,
DATEDIFF(year,GP_DATE,CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(month,GP_DATE)>10 THEN 0 ELSE 1 END
,GP_DATE)

How to get from a date column the last date of the previous month?

I have two date columns, which takes into account only working days. A_date and E_date.
E_date is calculated adding +2 days to A_date, because that's the request
The problem is that if the day of A_date is 30th or 31st of the month, then E_date date needs to be the last day of the current month, and not the first or second working day of the next month.
i have tried eomonth function but that does not work because it would need a explicit date.
Do you have any idea how to solve it?
You can use EOMONTH() in SQLServer to get the last day of the month.
Example:
EOMONTH(A_date)
SELECT CASE WHEN dateadd(month,1+datediff(month,0,A_date),-1)< DATEADD(day, 2, A_date) THEN dateadd(month,1+datediff(month,0,A_date),-1) ELSE DATEADD(day, 2, A_date) END E_date
FOR input of 2019/09/30 output is 2019-09-30 00:00:00.000
I'm not sure what your question is. What I've understood so far is that you want the last date of the month in case when adding two days to A_Date jumps to the next month.
Why don't you use CASE WHEN and compare out the months, this way :
DECLARE #A_Date date = '2019/09/30';
DECLARE #A_Date_Month int = 0;
DECLARE #E_Date_Month int = 0;
SELECT #A_Date_Month = Month(Cast(#A_Date AS datetime));
SELECT #E_Date_Month = Month(DATEADD(day, 2, #A_Date));
SELECT CASE
WHEN #A_Date_Month = #E_Date_Month
THEN DATEADD(day, 2, #A_Date)
ELSE EOMONTH(#A_Date) END AS OUTPUTValue
Try out the above set and do let me know if it resolves your issue!
How to get from a date column the last date of the previous month?
It depends on your RDBMS, so let's take the opportunity to make a generic answer:
In Oracle:
LAST_DAY(ADD_MONTHS(mydate ,-1))
In MySQL:
LAST_DAY(mydate - INTERVAL 1 MONTH)
In SQL Server:
DATEADD(MONTH, DATEDIFF(MONTH, -1, mydate )-1, -1)
-- or simply:
EOMONTH(DATEADD(Month, -1, mydate ))
In Postgres:
date_trunc('month', now())::mydate - 1
have two date columns, which takes into account only working days. A_date and E_date. E_date is calculated adding +2 days to A_date, because that's the request
I would simply do:
(case when dateadd(day, 2, a_date) < eomonth(a_date)
then dateadd(day, 2, a_date)
else eomonth(a_date)
end) as e_date
If you truly want this only on the 30th or 31st of any given month and not the last 2 days of any month (since obviously not every month has 31 days) --
select A_date
,case when day(A_date) >= 30
then eomonth(A_date)
else dateadd("dd",2,A_date)
end as E_date
Other answers work for "last 2 days of any month".

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.

last date of Financial year (I.e 2017-03-31)

Hi please let me know how to extract the last day of Financial year in sql server.my financial year start from 2016-04-01 to 2017-03-31
Closest you can use is End Of Month for that you need to provide one date to that month as below:
select eomonth('2017-03-01')
To get the last day of the financial year for any date, you need to find the last of march if before march, or the last of march next year if after march:
declare #yourdate datetime = getdate();
select case when month(#yourdate) < 4 then CONVERT(datetime,cast(YEAR(#yourdate) as char(4)) + '-03-31' ,120)
else CONVERT(datetime,cast(YEAR(#yourdate) + 1 as char(4)) + '-03-31' ,120)
end as financial_year_end
Edit:
If you want last date derived based on from_date, then use something like this
Rextester Demo
select
case when datepart(mm,from_date) <=3 then
cast(concat(year(from_date),'-03-31') as datetime)
else
dateadd(year,1,cast(concat(year(from_date),'-03-31') as datetime))
end as last_date_fin
from
(select '2017-04-30' as from_date union all
select '2017-01-13') t;
This way from_date between Jan - Mar will give same year's 31st march. Else it will give next year's 31st March.
Previous answer:
http://rextester.com/AXVM26769
If you want to get last day of march for same year as passed, then use
select cast(concat(given_year,'-03-31') as datetime)
from
(select '2017' as given_year) t
If you want to pass 2016 and then get 2017-03-31 then use. You can change the year in derived table and change the output based on that.
select dateadd(year,1,cast(concat(given_year,'-03-31') as datetime))
from
(select '2016' as given_year) t;
This Code will work to find the last date of Financial Year.
For Previous Year case matches and 'THEN' part will Execute and for current year 'ELSE'
part will execute.
select CASE WHEN (MONTH(GETDATE())) <= 3
THEN convert(varchar(4), YEAR(GETDATE())-1) + '-' + '03-31'
ELSE convert(varchar(4),YEAR(GETDATE()))+ '-' + '03-31'
end
> LastDayOfYearFY] =
> eomonth( dateadd(month, 5,
> dateadd(year, datepart(year, (dateadd(month, 6, [date])) ) -1900, 0)))
Idea extension taken from return-first-day-of-financial-year
You can select all the dates order them descendant and take the first one.
SELECT date
FROM table
ORDER BY date desc
LIMIT 1;

Sort by Date in SQL

I have a resources table, one of the fields is a date field with the Data Type of date. I want to have to following output:
Current month records (say May - year is not important)
Then the following (again, assuming May is the current month)
June Records
July Records
August Records
September Records
October Records
November Records
December Records
January Records
February Records
March Records
April Records
Come June, June is the current month and then the order would be:
July Records
August Records
...
Here is my SQL...I don't know how to ORDER the output to achieve the desired order (5,6,7,8,9,10,11,12,1,2,3,4):
SELECT
resource_id,
resource_title,
resource_summary,
resource_category,
resource_status,
resource_date,
DATEPART(month, resource_date) AS resource_month,
DATEPART(day, resource_date) AS resource_day
FROM dbo.resources
WHERE (resource_category = N'Quotes')
AND (resource_status <> N'Draft')
I found this possible solution for MySQL:
I need unusual ordering mysql results
but I'm missing something on my end.
ORDER BY
(MONTH(resource_date) - MONTH(GETDATE()) + 12) % 12,
DATEADD(year, YEAR(GETDATE()) - YEAR(resource_date), resource_date),
YEAR(resource_date)
The first term sets the primary order by the month of resource_date (the current month will be first, the previous one, last). The second term orders the timestamps within a month regardless of the year of the date. If your dates do not contain time parts or if the time parts are absolutely irrelevant, you could replace it with DAY(resource_date). Finally, the last term takes the year into account for otherwise identical dates (could also be simply resource_date).
Will it work for you?
ORDER BY
CASE DATEPART(month, resource_date)
WHEN 5 THEN 0
WHEN 6 THEN 1
... etc
END
I think something like this might be what you're looking for:
SELECT
resource_id,
resource_title,
resource_summary,
resource_category,
resource_status,
resource_date
FROM
dbo.resources
WHERE
resource_date >= DATE_FORMAT(NOW() ,'%Y-%m-01') AND
resource_date < DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 1 YEAR) ,'%Y-%m-01')
ORDER BY
resource_date;
How 'bout ORDER BY (DATEPART(month,resource_date) - (DATEPART(month,getdate() -1)) % 12)
So in May (month 5), you order by the month in the row -6 (mod 12). So, June (month 6) would be 0, July (7) would be 1.
In June, July would be 0, etc.
You should be able to adapt the MySQL solution by using DATEPART in place of DATE_FORMAT:
SELECT resource_id, resource_title, resource_summary, resource_category, resource_status, resource_date, DATEPART(month, resource_date) AS resource_month, DATEPART(day, resource_date) AS resource_day
FROM dbo.resources
WHERE (resource_category = N'Quotes') AND (resource_status <> N'Draft')
ORDER BY DATEPART(month, resource_date) < DATEPART(month, GETDATE()),
DATEPART(month, resource_date)
I don't have SQL Server handy so I'm not sure if it will be happy with a boolean in the ORDER BY clause though. If it doesn't like the boolean ORDER BY, then a CASE should do the trick:
ORDER BY
CASE WHEN DATEPART(month, resource_date) < DATEPART(month, GETDATE())
THEN 0
ELSE 1
END,
DATEPART(month, resource_date)
I assume that there is a year within "resource_date" - isn't it?
In this case you can simply filter and order by
WHERE resource_date >= getdate()
AND resource_date < DATEADD(year,1,getdate())
ORDER BY resource_date;
If there is no year (or more exactly: different unknown years) you can do this:
ORDER BY
CASE
WHEN DATEADD(year,-year(resource_date),resource_date) <
DATEADD(year,-year(getdate()),getdate())
THEN 1
ELSE 0
END ASC,
DATEADD(year,-year(resource_date),resource_date);
Hope it helped ...