понедельник, 19 мая 2014 г.

Использование рекурсии в CTE

Задачка:
Есть табличка с 3мя полями
ID DATE QTY

Для каждого клиента(ID) каждый день(DATE) может быть запись с количеством(QTY) N.
Нужно выбрать для каждого клиента(ID) все записи по такому принципу:
1. Находим для ID первую запись, где QTY больше 5 (если меньше - пропускаем) - выбираем эту запись
2. Находим для ID следующую запись, где QTY больше 5 и прошло не меньше 14 дней от даты предыдущей выбранной записи - выбираем эту запись
3. Повторяем итерацию 2, пока не выберем все записи

Решение.

Создаем табличку с тестовыми данными:

CREATE TABLE #tab (
 ID  integer,
 [DATE] datetime,
 QTY  integer
)

INSERT INTO #tab (ID,[DATE],QTY)
VALUES (1, '20140101', 5),(1, '20140102', 7), (1, '20140108', 2),
(1, '20140115', 12), (1, '20140122', 1),(1, '20140202', 2), 
(1, '20140208', 5), (1, '20140218', 8),(2, '20140101', 6),
(2, '20140102', 1), (2, '20140108', 11),(2, '20140115', 5), 
(2, '20140122', 8),(2, '20140202', 12), (2, '20140208', 3),
(2, '20140218', 6)


Я использовал рекурсию в CTE

WITH  a AS (
 SELECT * FROM (
  SELECT ID,
    [DATE],
    QTY,
    DATEADD(DAY, 14, [DATE]) AS MinNextDate ,
    ROW_NUMBER() OVER (PARTITION BY ID ORDER BY [DATE]) AS rn
  FROM #tab
  WHERE QTY > 5
 )b
 WHERE rn = 1



 UNION ALL

 SELECT
* FROM (
  SELECT c.ID,
    c.[DATE],
    c.QTY,
    DATEADD(DAY, 14, c.[DATE]) AS MinNextDate ,
    ROW_NUMBER() OVER (PARTITION BY c.ID ORDER BY c.[DATE]) AS rn
  FROM #tab c
    JOIN a
    ON c.ID =  a.ID
    AND c.[DATE] >= a.MinNextDate

  WHERE c.QTY > 5
 )b
 WHERE rn = 1

)


SELECT ID,[DATE], QTY
FROM a
ORDER BY ID, [DATE], QTY



Результат выполнения запроса:



Про рекурсию в CTE: http://www.sql-tutorial.ru/ru/book_recursive_cte/page3.html
 

Комментариев нет:

Отправить комментарий