Получить список значений года на основе разрыва и значения года в таблице - PullRequest
4 голосов
/ 17 мая 2019

Сценарий: у меня есть таблица со столбцами 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 с более чем одной записью в таблице.

Ответы [ 3 ]

3 голосов
/ 17 мая 2019

Это то, что вам нужно?

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 должен был бы выполнить большой объем рекурсии.

Демонстрация на db <> fiddle

1 голос
/ 17 мая 2019

Если по какой-либо причине вы предпочитаете рекурсивный 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];

Вам необходимо сохранить исходные параметры строки в рекурсивной части.таким образом, рекурсия выполняется по желанию.

1 голос
/ 17 мая 2019

Первоначально создайте одну пользовательскую функцию табличного типа, которая возвращает годы разрыва

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);

Запрос Sql для получения ожидаемого результата с использованием CROSS APPLY

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...