场景:我有一个包含Year
和Gap
列的表。我需要的输出是,从给定的年份值开始,一直递增到间隔列中的值。
即,如果YearVal
为2001,而Gap
为3,则需要输出为
Result
--------
2001
2002
2003
我尝试过的事情:
DECLARE @ResultYears TABLE (Gap INT, YearVal INT);
INSERT INTO @ResultYears (Gap, YearVal) VALUES (3, 2001);
;WITH FinalResult AS (
SELECT YearVal AS [YR] FROM @ResultYears
UNION ALL
SELECT [YR] + 1 FROM FinalResult
WHERE [YR] + 1 <= (SELECT YearVal + (Gap -1) FROM @ResultYears)
)
SELECT * FROM FinalResult;
db<>fiddle demo在表中有一个条目。
使用上面的查询,我可以达到预期的结果。但是,如果表中有多个条目,则该查询将无法正常工作。
即,如果我在下表中具有以下条目:
DECLARE @ResultYears TABLE (Gap INT, YearVal INT);
INSERT INTO @ResultYears (Gap, YearVal) VALUES
(3, 2001), (4, 2008), (1, 2014), (2, 2018);
如何修改查询以达到预期效果?
db<>fiddle demo在表中有多个条目。
答案 0 :(得分:3)
这是你的追求吗?
DECLARE @ResultYears TABLE (Gap INT, YearVal INT);
INSERT INTO @ResultYears (Gap, YearVal) VALUES
(3, 2001), (4, 2008), (1, 2014), (2, 2018);
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS I
FROM N N1, N N2), --100 is more than enough
Years AS(
SELECT RY.YearVal + T.I AS [Year],
RY.Gap,
RY.YearVal
FROM @ResultYears RY
JOIN Tally T ON RY.Gap > T.I)
SELECT *
FROM Years Y
ORDER BY Y.YearVal;
就个人而言,我更喜欢统计表而不是rCTE;它们的速度要快得多,尤其是对于大型数据集,或者rCTE必须进行大量递归的情况。
答案 1 :(得分:1)
最初创建一个用户定义的表类型函数,该函数将返回间隔年数
CREATE FUNCTION [dbo].[ufn_GetYears]
(
@i_Gap INT,@Year INT
)
RETURNS @Temp TABLE
(
Years INT
)
AS
BEGIN
;WITH CTE
AS
(
SELECT 1 AS Seq,DATEFROMPARTS ( @Year,01,01) AS Years
UNION ALL
SELECT seq +1,DATEADD(YEAR,1,Years)
FROM Cte
WHERE Seq < @i_Gap
)
INSERT INTO @Temp
SELECT DATEPART(YEAR,Years )
FROM CTE
RETURN
END
样本数据
DECLARE @ResultYears TABLE
(Gap INT,
YearVal INT
);
INSERT INTO @ResultYears (Gap, YearVal) VALUES
(3, 2001), (4, 2008), (1, 2014), (2, 2018);
使用CROSS APPLY进行Sql查询以获取预期结果
SELECT R.Gap,dt.Years
FROM @ResultYears R
CROSS APPLY [dbo].[ufn_GetYears](R.Gap,R.YearVal) AS dt
结果
Gap Years
---------
3 2001
3 2002
3 2003
4 2008
4 2009
4 2010
4 2011
1 2014
2 2018
2 2019
答案 2 :(得分:1)
如果出于某种原因,您更喜欢递归CTE(速度明显慢)
DECLARE @ResultYears TABLE (Gap INT, YearVal INT);
INSERT INTO @ResultYears (Gap, YearVal) VALUES (3, 2001), (4, 2008), (1, 2014), (2, 2018);
;WITH FinalResult AS (
SELECT YearVal, Gap, YearVal [YR] FROM @ResultYears
UNION ALL
SELECT YearVal, Gap, [YR] + 1
FROM FinalResult
WHERE [YR] + 1 <= YearVal + (Gap -1)
)
SELECT * FROM FinalResult
ORDER BY [YR];
您需要将原始行参数保留在递归部分中。这样,递归可以按需运行。