Как построить рекурсивную таблицу во встроенной табличной функции (iTVF)? - PullRequest
0 голосов
/ 01 октября 2019

У меня есть четыре параметра, которые должны быть приняты функцией:

@FromDate DATE, @ToDate DATE, @DataInterval INT, @RangeInterval INT

Результирующий набор получен с использованием CTE:

;WITH Dates_CTE (FromDt, ToDt) AS
(

SELECT
DATEADD(D,-@RangeInterval,@FromDate) AS [FromDt],
@FromDate AS [ToDt]

UNION ALL

SELECT
DATEADD(D,@DataInterval,D.FromDt) AS [FromDt],
DATEADD(D,@DataInterval,D.ToDt) AS [ToDt]
FROM Dates_CTE D
WHERE D.ToDt <= @ToDate
)

Но использование CTE делает еготабличная функция, и она становится убийцей производительности. Есть ли другой способ добиться этого во встроенной функции?

Пример желаемого результата с помощью ввода @FromDate = '20180701', @ToDate = '20180901', @DataInterval = 5, @RangeInterval = 30это:

+------------+------------+
|  FromDate  |   ToDate   |
+------------+------------+
| 2018-06-01 | 2018-07-01 |
| 2018-06-06 | 2018-07-06 |
| 2018-06-11 | 2018-07-11 |
| 2018-06-16 | 2018-07-16 |
| 2018-06-21 | 2018-07-21 |
| 2018-06-26 | 2018-07-26 |
| 2018-07-01 | 2018-07-31 |
| 2018-07-06 | 2018-08-05 |
| 2018-07-11 | 2018-08-10 |
| 2018-07-16 | 2018-08-15 |
| 2018-07-21 | 2018-08-20 |
| 2018-07-26 | 2018-08-25 |
| 2018-07-31 | 2018-08-30 |
| 2018-08-05 | 2018-09-04 |
+------------+------------+

Как мы можем достичь этого результата в iTVF? Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 01 октября 2019

На самом деле вам не нужна рекурсия. Используйте таблицу чисел. Здесь таблица чисел генерируется на лету, ее можно сохранить в БД для лучшей производительности.

DECLARE @FromDate DATE, @ToDate DATE, @DataInterval INT, @RangeInterval INT;
SELECT @FromDate = '20180701', @ToDate = '20180901', @DataInterval = 5, @RangeInterval = 30;
-- table of 1000 numbers starting 0
with t0(n) as (
 select n 
 from (
    values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
    ) t(n)
),nmbs as(
   select row_number() over(order by t1.n) - 1 n
   from t0 t1, t0 t2, t0 t3
)
select 
  DATEADD(D, @DataInterval*n - @RangeInterval, @FromDate) FromDate
  ,DATEADD(D, @DataInterval*n, @FromDate) ToDate
from nmbs
where DATEADD(D, @DataInterval*n , @FromDate) <= @ToDate;

Вам может потребоваться настроить условия, соответствующие вашим запросам.

Демонстрация с сохраненной таблицей чисел (также известной как таблица).

0 голосов
/ 01 октября 2019

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

CREATE TABLE Numbers (N INT PRIMARY KEY NOT NULL);

INSERT INTO Numbers
  SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) -1 N
  FROM
  (
      VALUES (NULL), (NULL), (NULL), (NULL), (NULL)
  ) T1(V) CROSS JOIN
  (
    VALUES (NULL), (NULL), (NULL), (NULL), (NULL)
  ) T2(VV) CROSS JOIN
  (
    VALUES (NULL), (NULL), (NULL), (NULL), (NULL) --Add Values as needed
  ) T3(VVV);

Затем создайте свою функцию как

CREATE FUNCTION dbo.MyFunc
(
  @FromDate DATE,
  @ToDate DATE,
  @DataInterval INT,
  @RangeInterval INT
)
RETURNS TABLE

  RETURN
  SELECT DATEADD(Day, (@DataInterval * N) - @RangeInterval, @FromDate) FromDate,
         DATEADD(Day, @DataInterval * N, @FromDate) ToDate
  FROM Numbers
  WHERE DATEADD(Day, @DataInterval * N, @FromDate) <= @ToDate;

И, наконец, используйте ее как

SELECT *
FROM dbo.MyFunc ('20180701', '20180901', 5, 30);

Демонстрация в Интернете

0 голосов
/ 01 октября 2019

вы можете использовать, пока:



declare @FromDate DATE = '20180701', @ToDate DATE= '20180901', @DataInterval INT= 5, @RangeInterval INT= 30,@date date ,@r int =0
declare @table table (d1 date, d2 date)

set @date= @FromDate
while (@date <@ToDate )
begin

insert into @table
select dateadd(d,@r,@FromDate ),DATEADD(D,-@RangeInterval+@r,@FromDate)

set @r=@r+@DataInterval
set @date = dateadd(d,@r,@FromDate )
end 

select * from @table
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...