SQL to SELECT最后4个财务季度

时间:2018-03-28 04:59:05

标签: sql sql-server tsql refactoring finance

我正在学习SQL,我有这个看起来很糟糕的查询来选择过去4个财政/财政季度以及它们之前的几个季度。

  • 这是使用澳大利亚财政年度(6月至7月)
  • 2018财政年度为2017年7月至2018年6月
  • FinancialQuarterID的结构类似于YYYYQ

如果日期是2018年3月28日,则返回的表格如下:

╔═══╦════════════╦═════════════╗  
║   ║ ID         ║ QuartersAgo ║  
╠═══╬════════════╬═════════════╣  
║ 1 ║ 20182      ║ 1           ║  
║ 2 ║ 20181      ║ 2           ║  
║ 3 ║ 20174      ║ 3           ║  
║ 4 ║ 20173      ║ 4           ║  
╚═══╩════════════╩═════════════╝  

我的查询如下。当然有一个更好,更有效的方式......我喜欢这个是它的工作原理,我可以将它提交到版本控制(不像Excel和PowerBI,我通常会建立这个东西)。

在第一阶段,我根据日历年的月份确定财政年度。

以类似的方式,我将这些年份分解为Quarters以确定当前的财务季度。

一旦我发现我正在设置和确定第n季度前的值。

我不喜欢的是我觉得我应该只是将值插入变量表中,因为我正在确定我是哪个季度。相反,我指定一个值,然后稍后插入。

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

会感激一些反馈:)谢谢

2 个答案:

答案 0 :(得分:3)

拯救的递归CTE:

;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

这是输出:

FinancialQuarter    QuartersAgo
20182               1
20181               2
20174               3
20173               4

以下是一些要点:

  1. 要获得今天作为澳大利亚财政季度的日期,请加上3个月并将该年度结束到该季度(您可以通过DATEPART(季度(日期))获得,所以,像这样:< / p>

    CAST(年(DATEADD(月,3,GETDATE()))AS VARCHAR(4))+ CAST(DATEPART(QUATTER,DATEADD(月,3,GETDATE()))AS VARCHAR(1))

  2. CTE(公用表表达式)有点像临时表 这是查询的范围。这是一个简单的解释。热膨胀系数 值得一读!
  3. 您可以使用创建递归CTE UNION ALL - UNION ALL之前的查询部分 锚点,然后是递归部分。在这种情况下,我使用 在哪里QuartersAgo&lt; 4,几个后停止查询递归 工会。
  4. CTE以; WITH开头 - 所有CTE都以&#34; WITH&#34;开头, 而分号只是终止任何悬挂的chads 悬挂在CTE定义面前。
  5. 括号后 围绕CTE定义,您可以从CTE查询。但是只有 一旦。之后,CTE超出了范围。
  6. 可以筑巢 一堆CTE - 一个CTE可以引用它之前的CTE,但不是 那些跟随它的人。

答案 1 :(得分:0)

我还使用Recursive CTE来解决此问题(我确实从@Max解决方案中获取了帮助) -

declare @Today date = getdate()
declare @CalendarMonth int = datepart(month, @Today)
declare @LastFinancialQuarterDate date = dateadd(month, (case when @CalendarMonth <= 6 then 6 else 18 end) - @CalendarMonth, @Today)

;with cte as
(
    select  cast(datepart(year, @LastFinancialQuarterDate) as varchar(4))
            +
            cast(datepart(quarter, @LastFinancialQuarterDate) as varchar(1)) as ID,
            1 as QuartersAgo
    union all
    select  cast(datepart(year, dateadd(month, cte.QuartersAgo * -3, @LastFinancialQuarterDate)) as varchar(4))
            +
            cast(datepart(quarter, dateadd(month, cte.QuartersAgo * -3, @LastFinancialQuarterDate)) as varchar(1)) as ID,
            (cte.QuartersAgo + 1) as QuartersAgo
    from cte
    where cte.QuartersAgo < 4
)
select * from cte

我做的第一件事就是找到属于上一个澳大利亚季度的日期并将其设置为@LastFinancialQuarterDate变量。之后我在Recursive CTE中使用该变量来遍历过去的四个季度。