How to get the financial years - sql

I have requirement where is need to get financial years staring from 2019 to current year,
Output required:
2019-2020
2020-2021
2021-2022
2022-2023
Please find help me out with SQL query for required format.
Note: next year it should come dynamically 2023-2024.
SELECT #FIYear AS F_YEAR
SELECT QM_FIN_YEAR =
CASE
WHEN Month(GETDATE()) BETWEEN 4 AND 12
THEN CONVERT(VARCHAR(4),YEAR(GETDATE())) + '-' + CONVERT(VARCHAR(4),YEAR(GETDATE()) + 1)
WHEN Month(GETDATE()) BETWEEN 1 AND 3
THEN CONVERT(VARCHAR(4),YEAR(GETDATE()) - 1) + '-' + CONVERT(VARCHAR(4),YEAR(GETDATE()) )
End ORDER by 1 DESC

You can get the desired result with below query
WITH cte_Years AS (
SELECT YEAR(GETDATE())-1 AS start_year, YEAR(GETDATE()) AS end_year
UNION ALL
SELECT start_year-1, end_year-1
FROM cte_Years
WHERE start_year-1 >= 2019
)
SELECT CONCAT(start_year, '-', end_year) AS financial_year
FROM cte_Years
ORDER BY end_year

If you're using the latest version of SQL Server this is very easy using generate_series
with years as (select value y from generate_series(2019, year(getdate()) - 1))
select concat_ws('-', y, y + 1) FinancialYear
from years;
Fiddle Demo

Related

SQL Server the closest 1st February

Could you please help in finding the closest February 1st to current date?
The following script works correctly only if it is ran in current year:
select DATEADD(MONTH,1,DATEADD(year, DATEDIFF(year, -1, GETDATE()), 0))
But when it would be ran in January next year it will produce incorrect result.
Thank you in advance!
Your question can be interpreted two different ways: the first being to find the next closest Feb 1 (i.e. Feb 2 2016 will return Feb 1 2017), and the second being to find the closest Feb 1 to the current date (i.e. Feb 2 2016 will return Feb 1 2016).
Prdp has already supplied an answer for the former, so this approach (which I'm sure can be simplified) will be for the latter.
This will consider the current year's Feb 1 and the next year's Feb 1, and compute the DateDiff() in days from both, and select the closest one.
;With Dates As
(
Select ThisFeb = DateFromParts(Year(GetDate()), 2, 1),
NextFeb = DateFromParts(Year(GetDate()) + 1, 2, 1)
), Distance (Date, Distance) As
(
Select ThisFeb, Abs(DateDiff(Day, GetDate(), ThisFeb)) As ThisFebDiff
From Dates
Union All
Select NextFeb, Abs(DateDiff(Day, GetDate(), NextFeb)) As NextFebDiff
From Dates
)
Select Top 1 Date
From Distance
Order By Distance Asc
Try something like this using IIF and DATEFROMPARTS
select IIF(month(getdate()) > 2,
DATEFROMPARTS(YEAR(Getdate()),2,1),DATEFROMPARTS(YEAR(Getdate())-1,2,1) )
If you are using older versions then
select Case When month(getdate()) > 2
then CAST(CAST(YEAR(getdate()) as char(4))+'-02-01' as date)
else CAST(CAST(YEAR(getdate()) - 1 as char(4))+'-02-01' as date)
end
Try This:
SELECT
CASE WHEN
DATEDIFF(dd,CAST(CONCAT(year(GETDATE()),'-02-01') AS DATE),GETDATE()) < 183
THEN CAST(CONCAT(year(GETDATE()),'-02-01') AS DATE)
ELSE CAST(CONCAT(year(GETDATE())+1,'-02-01') AS DATE) END as ClosestFebFirst
This is another possible solution...
DECLARE #SomeDate DATE = '2017-06-30';
SELECT TOP 1
ClosestFebFirst = CASE WHEN dd.Diff1 < dd.Diff2 THEN pd.D1 ELSE pd.D2 END
FROM
( VALUES (
DATEFROMPARTS(YEAR(#SomeDate), 2, 1),
DATEFROMPARTS(YEAR(#SomeDate) + 1, 2, 1)
)
) pd (D1, D2)
CROSS APPLY ( VALUES (
ABS(DATEDIFF(dd, #SomeDate, pd.D1)),
ABS(DATEDIFF(dd, #SomeDate, pd.D2))
)
) dd (Diff1, Diff2);

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;

Grouping by year and month on date stored as a decimal

I have a data set with the following sample information:
ID DTE CNTR
1 20110102.0 2
1 20110204.0 3
1 20110103.0 5
2 20110205.0 6
2 20110301.0 7
2 20110302.0 3
If I want to group the information by month and sum the counter, the code I'm guessing would be this:
SELECT t.ID,
,SUM CASE(WHEN t.DTE between 20110101 and 20110131 then t.CNTR else 0) as Jan
,SUM CASE(WHEN t.DTE between 20110201 and 20110228 then t.CNTR else 0) as Feb
,SUM CASE(WHEN t.DTE between 20110301 and 20110331 then t.CNTR else 0) as Mar
FROM table t
GROUP BY t.ID
But, is there a way to aggregate that information into another two columns called "month" and "year" and group it that way, leaving me flexibility to preform select queries over many different time periods?
Edit, since your datatype is a decimal, you can use the following:
select ID,
left(dte, 4) year,
SUBSTRING(cast(dte as varchar(8)), 5, 2) mth,
sum(CNTR) Total
from yt
group by id, left(dte, 4), SUBSTRING(cast(dte as varchar(8)), 5, 2)
My suggestion would be to use the correct datatype for this which would be datetime. Then if you want the data for each month in columns, then you can use:
SELECT t.ID
, SUM(CASE WHEN t.DTE between '20110101' and '20110131' then t.CNTR else 0 end) as Jan
, SUM(CASE WHEN t.DTE between '20110201' and '20110228' then t.CNTR else 0 end) as Feb
, SUM(CASE WHEN t.DTE between '20110301' and '20110331' then t.CNTR else 0 end) as Mar
, year(dte)
FROM yt t
GROUP BY t.ID, year(dte);
This query includes a column to get the year for each DTE value.
If you want the result in multiple rows instead of columns, then you can use:
select ID,
YEAR(dte) year,
datename(m, dte) month,
sum(CNTR) Total
from yt
group by id, year(dte), datename(m, dte);
Note, this assumes that the DTE is a date datatype.
Another idea - using div/modulo operators:
select (dte / 10000) dte_year, ((dte % 10000) / 100) dte_month,sum(cntr)
from tablename
group by (dte / 10000) , ((dte % 10000) / 100)
select id,
datepart(yy, convert(datetime, dte, 112)),
datepart(mm, convert(datetime, dte, 112)),
sum(cntr)
from table
group by id,
datepart(yy, convert(datetime, dte, 112)),
datepart(mm, convert(datetime, dte, 112))

finding records relative to today

I have a table named dbstorage which has columns like year and weekno.
I need to select the year and weekno which is less than current year and current week.
I used:
select * from dbstorage where year<=2011 and weekno<=13.
But it is not giving the correct data like if I have a value
year:2010 and weekno:25 means, the query is not selecting this record.
How can this be done?
You can split it out into two cases and use or
SELECT * /*<-- But don't use * List the columns explicitly*/
FROM dbstorage
WHERE ( year = 2011
AND weekno <= 13 )
OR year < 2011
Edit
But And logic may well be more efficient
SELECT *
FROM dbstorage
WHERE ( year <= 2011 )
AND ( year < 2011
OR weekno <= 13 )
you have to split up the search into multiple parts:
select * from dbstorage
where
(year = 2011 and weekno <= 13) -- will catch all weeks in 2011 PRIOR to this one
or (year < 2011) -- will catch all weeks in 2010 and earlier
For SQL Server you can also do:
SELECT *
FROM dbstorage
WHERE (year = DATEPART(yyyy, GETDATE())
AND weekno <= DATEPART(ww, GETDATE()))
OR year < DATEPART(yyyy, GETDATE())

Date split-up based on Fiscal Year

Given a From Date, To Date and a Fiscal Year system, I want to get all the split-up duration within the
given From & To Date based on the Fiscal Year system. Explained below with examples:
Example 1:
Fiscal Year system: Apr to Mar
From Date: Jan-05-2008
To Date: May-15-2008
Based on Fiscal Year system, duration should be splitted into:
Jan-05-2008 to Mar-31-2008
Apr-01-2008 to May-15-2008
Example 2:
Fiscal Year system: Apr to Mar
From Date: Jan-17-2008
To Date: May-20-2009
Based on Fiscal Year system, duration should be splitted into:
Jan-17-2008 to Mar-31-2008
Apr-01-2008 to Mar-31-2009
Apr-01-2009 to May-20-2009
Am looking for approach/algorithm to solve this in PostgreSQL 8.2.
Regards,
Gnanam
I actually favor Andomar's solution (with the addition of a processes that automatically fills the Periods table), but for fun here's a solution that doesn't require it.
CREATE TABLE your_table (start_date date, end_date date);
INSERT INTO your_table VALUES ('Jan-17-2008', 'May-20-2009');
SELECT
GREATEST(start_date, ('04-01-'||series.year)::date) AS year_start,
LEAST(end_date, ('03-31-'||series.year + 1)::date) AS year_end
FROM
(SELECT
start_date,
end_date,
generate_series(
date_part('year', your_table.start_date - INTERVAL '3 months')::int,
date_part('year', your_table.end_date - INTERVAL '3 months')::int)
FROM your_table) AS series(start_date, end_date, year)
ORDER BY
start_date;
You could create a table containing the start and end of all fiscal years, f.e.
Periods (PeriodStartDt, PeriodEndDt)
Then you can join the tables together if they at least partly overlap. Use a case statement to select the end of the period or the end of the row, depending on which is later. For example (not tested):
select case when yt.StartDt < p.PeriodStartDt then p.PeriodStartDt
else yt.StartDt
end as SplitStart
, case when yt.EndDt > p.PeriodEndDt then p.PeriodEndDt
else yt.EndDt
end as SplitEnd
, yt.*
from YourTable yt
inner join Periods p
on yt.StartDt < p.PeriodEndDate
and yt.EndDt >= p.PeriodStartDate
CREATE TABLE your_table (start_date date, end_date date);
INSERT INTO your_table VALUES (CONVERT (date, GETDATE()),CONVERT (date, DATEADD(year, -1, GETDATE())) );
WITH mycte AS
(
SELECT 1 as id
UNION ALL
SELECT id + 1
FROM mycte
WHERE id + 1 < = 12
),
cte_distribution as
(
SELECT *,
DATEPART (month,DATEADD(month, mycte.id - 1, your_table.start_date)) as month_number ,
DATEPART (YEAR,DATEADD(month, mycte.id - 1, your_table.start_date)) as cal_year,
12000/12 as cash
FROM your_table
CROSS JOIN mycte
)
select
*,
(CASE WHEN month_number between 1 and 3 THEN '1st quarter' WHEN month_number between 4 and 6 THEN '2nd quarter' WHEN month_number between 7 and 9 THEN '3rd quarter' WHEN month_number between 9 and 12 THEN '4th quarter' END) as Quarter,
CASE WHEN month_number between 1 and 6 THEN CAST(CAST((cal_year - 1) as CHAR(4)) + '-' + CAST(cal_year as CHAR(4)) AS CHAR(9)) WHEN month_number between 6 and 12 THEN CAST(CAST((cal_year) as CHAR(4)) + '-' + CAST((cal_year + 1) as CHAR(4)) AS CHAR(9)) ELSE NULL END as fin_year
from cte_distribution;