I'm learning SQL and I have this horrible looking query to select the last 4 financial/fiscal quarters and how many quarters ago they were.
If the date is 28th March 2018 then the table returned is like:
╔═══╦════════════╦═════════════╗
║ ║ ID ║ QuartersAgo ║
╠═══╬════════════╬═════════════╣
║ 1 ║ 20182 ║ 1 ║
║ 2 ║ 20181 ║ 2 ║
║ 3 ║ 20174 ║ 3 ║
║ 4 ║ 20173 ║ 4 ║
╚═══╩════════════╩═════════════╝
My query is below. Surely there is a much better and more efficient way... What I like about this is that it works and I can commit it to version control (unlike Excel and PowerBI that I would usually build this thing in).
In the first phase I am determining the financial year based on the month of the calendar year.
In a similar way I am then breaking the years down into Quarters to determine the current financial quarter.
Once I have found that I am setting and determining values for the nth quarter ago.
What I don't like is that I feel like I should just be inserting values into the variable table as I am determining which quarter I am. Instead I assign to a value and then insert that later on.
DECLARE @Today DATE = GETDATE();
DECLARE @ThisCalendarYear VARCHAR(4)
DECLARE @ThisFinancialYear VARCHAR(4)
DECLARE @ThisCalendarMonth INT
DECLARE @Last4FinancialQuarters TABLE(
ID VARCHAR(5) NOT NULL,
QuartersAgo INT NOT NULL
);
DECLARE @LastFinancialQuarter VARCHAR(5)
DECLARE @SecondLastFinancialQuarter VARCHAR(5)
DECLARE @ThirdLastFinancialQuarter VARCHAR(5)
DECLARE @FourthLastFinancialQuarter VARCHAR(5)
SET @ThisCalendarYear = DatePart(Year, @Today)
SET @ThisCalendarMonth = DatePart(Month, @Today)
IF DatePart(Month, @Today) <= 6
SET @ThisFinancialYear = DatePart(Year, @Today)
ELSE
SET @ThisFinancialYear = DatePart(Year, @Today) +1
SET @LastFinancialQuarter = CASE
WHEN @ThisCalendarMonth <= 3 THEN CONCAT(@ThisCalendarYear ,4 - 2)
WHEN @ThisCalendarMonth <= 6 THEN CONCAT(@ThisCalendarYear ,4 - 1)
WHEN @ThisCalendarMonth <= 9 THEN CONCAT(@ThisCalendarYear ,4 - 0)
WHEN @ThisCalendarMonth <= 12 THEN CONCAT(@ThisCalendarYear + 1,4 - 3)
END
SET @SecondLastFinancialQuarter = CASE
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 4 THEN CONCAT(@ThisFinancialYear,3)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 3 THEN CONCAT(@ThisFinancialYear,2)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 2 THEN CONCAT(@ThisFinancialYear,1)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 4 THEN CONCAT(@ThisFinancialYear - 1,4)
END
SET @ThirdLastFinancialQuarter = CASE
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 4 THEN CONCAT(@ThisFinancialYear,2)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 3 THEN CONCAT(@ThisFinancialYear,1)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 2 THEN CONCAT(@ThisFinancialYear - 1,4)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 4 THEN CONCAT(@ThisFinancialYear - 1,3)
END
SET @FourthLastFinancialQuarter = CASE
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 4 THEN CONCAT(@ThisFinancialYear,1)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 3 THEN CONCAT(@ThisFinancialYear - 1,4)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 2 THEN CONCAT(@ThisFinancialYear - 1,3)
WHEN SUBSTRING(@LastFinancialQuarter, 5,1) = 4 THEN CONCAT(@ThisFinancialYear - 1,2)
END
INSERT INTO @Last4FinancialQuarters (ID, QuartersAgo)
VALUES
(@LastFinancialQuarter, 1),
(@SecondLastFinancialQuarter, 2),
(@ThirdLastFinancialQuarter, 3),
(@FourthLastFinancialQuarter, 4);
SELECT * FROM @Last4FinancialQuarters
Would appreciate some feedback :) Thanks
Recursive CTE to the rescue:
;WITH cte AS
(
SELECT 1 as QuartersAgo, GETDATE() as DT,
CAST(YEAR(DATEADD(MONTH, 3, GETDATE())) AS VARCHAR(4)) + CAST(DATEPART(QUARTER, DATEADD(MONTH, 3, GETDATE())) AS VARCHAR(1)) as FinancialQuarter
UNION ALL
SELECT QuartersAgo + 1, DATEADD(MONTH, -3, cte.DT),
CAST(YEAR(DATEADD(MONTH, 3, DATEADD(MONTH, -3, cte.DT))) AS VARCHAR(4)) + CAST(DATEPART(QUARTER, DATEADD(MONTH, 3, DATEADD(MONTH, -3, cte.DT))) AS VARCHAR(1))
FROM cte
WHERE QuartersAgo < 4
)
SELECT FinancialQuarter, QuartersAgo FROM cte
Here's the output:
FinancialQuarter QuartersAgo
20182 1
20181 2
20174 3
20173 4
Here are some important points:
To get today's date as an Australian fiscal quarter, add 3 months and concat the year to the quarter (which you can get with DATEPART(QUARTER(DATE)), so, like this:
CAST(YEAR(DATEADD(MONTH, 3, GETDATE())) AS VARCHAR(4)) + CAST(DATEPART(QUARTER, DATEADD(MONTH, 3, GETDATE())) AS VARCHAR(1))