我遇到一个问题,我需要确定财务季度,但并不总是知道季度的开始/结束日期。然而,它们总是 3 个月长。我所知道的是当前季度的结束日期,以及所指的季度和年份。例如,我可能会得到:
当前季度:第四季度
当前年份:2021
当前季度结束日期:2021 年 1 月 31 日
如何获取其他日期的季度?如果这 3 个值中的任何一个发生更改,查询仍然需要根据这 3 个参数提供任何给定日期的季度。
我想出了以下方法,将过去 4 年的数据放入临时表中:
DECLARE @QuarterEnd DATE = '1/31/2022'
, @CurrentQuarter INT = 1
, @CurrentYear INT = 2022
, @Counter INT = 16
, @qs INT = 0
, @qe INT = 2
, @DateToTest DATE = '12/15/2021'
CREATE TABLE #Quarters (
StartDate DATE
, EndDate DATE
, Qtr INT
, Yr INT
)
WHILE @Counter <> 0
BEGIN
INSERT INTO #Quarters VALUES (
cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, @QuarterEnd)-@qe , 0) as date)
, cast(DATEADD(MONTH, DATEDIFF(MONTH, -1, @QuarterEnd)-@qs, -1) as date)
, @CurrentQuarter
, @CurrentYear
)
SET @Counter = @Counter - 1
SET @qs = @qs + 3
SET @qe = @qe + 3
SET @CurrentQuarter = CASE WHEN @CurrentQuarter = 1 THEN 4 ELSE @CurrentQuarter - 1 END
SET @CurrentYear = CASE WHEN @CurrentQuarter = 4 THEN @CurrentYear - 1 ELSE @CurrentYear END
END
SELECT @DateToTest
, (SELECT CONCAT('Q', Qtr, ' ', Yr) FROM #Quarters WHERE @DateToTest BETWEEN StartDate and EndDate)
FROM #Quarters
但是,当我运行将返回数十万条记录的查询时,这似乎并不实用。
我想我可以将其放入一个函数中并使用以下方式调用它:
SELECT MyQuarter = dbo.MyQuarterFunction(@QuarterEnd, @CurrentQuarter, @CurrentYear, @DateToTest)
必须有一种更有效的方法来做到这一点。有什么建议吗?
最佳答案
只需创建一个名为 Quarters
的永久表即可。
CREATE TABLE dbo.Quarters
(
StartDate date,
QuarterNumber tinyint,
FiscalYear int,
NextQuarterStartDate AS (DATEADD(MONTH, 3, StartDate))
);
INSERT dbo.Quarters(StartDate, QuarterNumber, FiscalYear)
VALUES('20200201',1,2020),
('20200501',2,2020),
('20200801',3,2020),
('20201101',4,2020),
('20210201',1,2021),
('20210501',2,2021),
('20210801',3,2021),
('20211101',4,2021),
('20220201',1,2022),
('20220501',2,2022),
('20220801',3,2022),
('20221101',4,2022);
现在,只要给您一个日期(例如 GETDATE()
),您就可以轻松找到其他信息:
DECLARE @date date = GETDATE();
SELECT * FROM dbo.Quarters
WHERE @date >= StartDate
AND @date < NextQuarterStartDate;
- 示例 db<>fiddle
如果您需要同时支持多个会计日历,只需添加一列(例如 CalendarID
或 CompanyID
或 CustomerID
)。
实际上,您甚至不需要日历或季度表。你已经有一 table 客户了,对吧?只需添加一列来存储其财政年度开始的月份。这确实是您所需要的。
CREATE TABLE dbo.Clients
(
ClientID int NOT NULL CONSTRAINT PK_Clients PRIMARY KEY,
Name nvarchar(200) NOT NULL CONSTRAINT UQ_ClientName UNIQUE,
FiscalYearStart tinyint NOT NULL CONSTRAINT CK_ValidMonth
CHECK (FiscalYearStart BETWEEN 1 AND 12)
);
现在让我们插入一些包含不同会计年度的客户的几行:
INSERT dbo.Clients(ClientID, Name, FiscalYearStart)
VALUES(1, N'ClientFeb', 2), -- fiscal year starts in February
(2, N'ClientMay', 5), -- fiscal year starts in May
(3, N'ClientNormal', 1); -- fiscal year matches calendar
现在,是的,我们需要一个函数,但我们不要执行任何 while 循环、计数器或 #temp 表。
CREATE FUNCTION dbo.GetLast16Quarters
(
@DateToTest date,
@ClientID int
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
(
WITH n(n) AS
(
SELECT n = 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 20
),
Last20Quarters(QuarterStart, FiscalYearStart) AS
(
SELECT QuarterStart = DATEADD(QUARTER, 1-n,
DATEFROMPARTS(YEAR(@DateToTest)+1, FiscalYearStart, 1)),
FiscalYearStart
FROM dbo.Clients CROSS JOIN n WHERE ClientID = @ClientID
),
Last16Quarters AS
(
SELECT TOP (16) QuarterStart,
y = YEAR(DATEADD(MONTH, 1-FiscalYearStart, QuarterStart))
FROM Last20Quarters WHERE QuarterStart < @DateToTest
ORDER BY QuarterStart DESC
)
SELECT QuarterStart,
QuarterEnd = EOMONTH(QuarterStart, 2),
FiscalYear = y,
QuarterNumber = ROW_NUMBER() OVER
(PARTITION BY y ORDER BY QuarterStart)
FROM Last16Quarters);
然后调用它:
DECLARE @DateToTest date = '20211215';
SELECT * FROM dbo.GetLast16Quarters(@DateToTest, 1);
输出:
QuarterStart QuarterEnd FiscalYear QuarterNumber 2018-02-01 2018-04-30 2018 1 2018-05-01 2018-07-31 2018 2 2018-08-01 2018-10-31 2018 3 2018-11-01 2019-01-31 2018 4 2019-02-01 2019-04-30 2019 1 2019-05-01 2019-07-31 2019 2 2019-08-01 2019-10-31 2019 3 2019-11-01 2020-01-31 2019 4 2020-02-01 2020-04-30 2020 1 2020-05-01 2020-07-31 2020 2 2020-08-01 2020-10-31 2020 3 2020-11-01 2021-01-31 2020 4 2021-02-01 2021-04-30 2021 1 2021-05-01 2021-07-31 2021 2 2021-08-01 2021-10-31 2021 3 2021-11-01 2022-01-31 2021 4
- 示例 db<>fiddle
关于sql - 给定示例结束日期和季度编号,计算日期的季度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71444759/