根据表中的差距和年份值获取年份值列表

时间:2019-05-17 13:19:23

标签: sql sql-server

场景:我有一个包含YearGap列的表。我需要的输出是,从给定的年份值开始,一直递增到间隔列中的值。

即,如果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在表中有多个条目。

3 个答案:

答案 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必须进行大量递归的情况。

Demo on db<>fiddle

答案 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];

您需要将原始行参数保留在递归部分中。这样,递归可以按需运行。