Генерация последовательных месяцев в SQL - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть таблица, подобная приведенной ниже. Пример:

code |  date       | value
1000   2016-08-05    5000
1000   2016-12-27    8000
1000   2018-03-19    6000
1000   2018-06-02    6000

Теперь мне нужно сгенерировать последовательные месяцы, подобные этой:

code |  date       | value
1000   2016-08-05    5000
1000   2016-09-05    5000
1000   2016-10-05    5000
1000   2016-11-05    5000
1000   2016-12-27    8000
1000   2017-01-27    8000
1000   2017-02-27    8000
........
1000   2018-03-19    6000
1000   2018-04-19    6000
1000   ....

Последовательность продолжается, пока не достигнет максимальной датыкод. В этом примере максимальная дата 2018-06-02 для кода 1000. Как я могу сгенерировать последовательность месяцев? Любая помощь будет высоко ценится.

Ответы [ 2 ]

3 голосов
/ 05 ноября 2019

Попробуйте:

DECLARE @DataSource TABLE
(
    [Code] INT
   ,[Date] DATE
   ,[value] INT
);

INSERT INTO @DataSource ([Code], [Date], [value])
VALUES (1000, '2016-08-05', 5000)
      ,(1000, '2016-12-27', 8000)
      ,(1000, '2018-03-19', 6000)
      ,(1000, '2018-06-02', 6000);

WITH Ranges AS
(
    SELECT *
          ,LEAD([Date]) OVER (ORDER BY [Date] ASC) AS [DateEnd]
    FROM @DataSource DS
)
SELECT *
FROM Ranges
CROSS APPLY
(
    SELECT DATEADD(MONTH, [number], [Date])
    FROM 
    (
        select number 
        from master.dbo.spt_values
        where [type] = 'P'
    ) numbers
    WHERE DATEADD(MONTH, [number], [Date]) < [DateEnd]
) AutoDates ([GeneratedDate]);

enter image description here

Идея проста - с помощью LEAD получить верхнюю границу диапазона дат. Затем, имея дату начала и окончания, просто сгенерируйте недостающие месяцы, используя функцию DATEADD.

2 голосов
/ 05 ноября 2019

Одним из решений было бы создание таблицы чисел в рекурсивном CTE, а затем соединение с таблицей. Вы можете использовать условие соединения not exists, чтобы определить границы каждой серии: я понимаю, что вам нужна только одна дата в месяц (без пропусков и перекрытий в одном и том же месяце), поэтому я использовал для этого eomonth().

Запрос:

with nums(i) as (
    select 0
    union all select i + 1 from nums where i < 24
)
select 
    t.code,
    dateadd(month, i, t.date) date,
    t.value
from mytable t
inner join nums n 
    on not exists (
        select 1
        from mytable t1
        where t1.date > t.date and eomonth(t1.date) < eomonth(dateadd(month, i + 1, t.date))
    )
order by date

Вы можете расширить верхний предел в cte до максимального количества последовательных месяцев (я установил его на 24).

Демо на БД Fiddle :

code | date                | value
---: | :------------------ | ----:
1000 | 05/08/2016 00:00:00 |  5000
1000 | 05/09/2016 00:00:00 |  5000
1000 | 05/10/2016 00:00:00 |  5000
1000 | 05/11/2016 00:00:00 |  5000
1000 | 27/12/2016 00:00:00 |  8000
1000 | 27/01/2017 00:00:00 |  8000
1000 | 27/02/2017 00:00:00 |  8000
1000 | 27/03/2017 00:00:00 |  8000
1000 | 27/04/2017 00:00:00 |  8000
1000 | 27/05/2017 00:00:00 |  8000
1000 | 27/06/2017 00:00:00 |  8000
1000 | 27/07/2017 00:00:00 |  8000
1000 | 27/08/2017 00:00:00 |  8000
1000 | 27/09/2017 00:00:00 |  8000
1000 | 27/10/2017 00:00:00 |  8000
1000 | 27/11/2017 00:00:00 |  8000
1000 | 27/12/2017 00:00:00 |  8000
1000 | 27/01/2018 00:00:00 |  8000
1000 | 27/02/2018 00:00:00 |  8000
1000 | 19/03/2018 00:00:00 |  6000
1000 | 19/04/2018 00:00:00 |  6000
1000 | 19/05/2018 00:00:00 |  6000
1000 | 02/06/2018 00:00:00 |  6000
1000 | 02/07/2018 00:00:00 |  6000
1000 | 02/08/2018 00:00:00 |  6000
1000 | 02/09/2018 00:00:00 |  6000
1000 | 02/10/2018 00:00:00 |  6000
1000 | 02/11/2018 00:00:00 |  6000
1000 | 02/12/2018 00:00:00 |  6000
1000 | 02/01/2019 00:00:00 |  6000
1000 | 02/02/2019 00:00:00 |  6000
1000 | 02/03/2019 00:00:00 |  6000
1000 | 02/04/2019 00:00:00 |  6000
1000 | 02/05/2019 00:00:00 |  6000
1000 | 02/06/2019 00:00:00 |  6000
1000 | 02/07/2019 00:00:00 |  6000
1000 | 02/08/2019 00:00:00 |  6000
1000 | 02/09/2019 00:00:00 |  6000
1000 | 02/10/2019 00:00:00 |  6000
1000 | 02/11/2019 00:00:00 |  6000
1000 | 02/12/2019 00:00:00 |  6000
1000 | 02/01/2020 00:00:00 |  6000
1000 | 02/02/2020 00:00:00 |  6000
1000 | 02/03/2020 00:00:00 |  6000
1000 | 02/04/2020 00:00:00 |  6000
1000 | 02/05/2020 00:00:00 |  6000
1000 | 02/06/2020 00:00:00 |  6000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...