2015-06-10 5 views
2

У меня есть таблица, которая содержит много строк (в настоящее время 500K, как ожидается, возрастет до 15 миллионов в течение следующих 3 лет). В таблице указаны платежи, сделанные за определенное событие за определенный день. И событие может иметь 1 или много платежей за тот же день, но платежи в тот же день должны иметь разные PaymentTypes.Получите смежные диапазоны дат, сгруппированных в одну строку

Ниже приведено описание переменной таблицы, которое создает базовые данные (ввод), а затем выбирается жесткий диск, который является ожидаемым выходом. Мне нужно группировать непрерывные диапазоны дат для типа оплаты, для размещения в одной строке с датой «От» и «До», а затем, когда есть разрыв - нет строк, а затем для следующего диапазона дат.

Например:

Размещение 1 не получили выплаты от 1-го до 2-го (2 дня) для компенсации типа 5, а затем с 4-го до 6-го для того же типа. Следовательно, две строки. Тип оплаты 1 также получил платеж за 1-й по 3-й для типа оплаты 10. Итак, это еще одна строка.

DECLARE @Temp TABLE 
(
    Id INT NOT NULL IDENTITY(1,1), 
    PlacementId INT NOT NULL, 
    PaymentTypeId INT NOT NULL, 
    DateValue DATETIME NOT NULL, 
    Amount DECIMAL(16,2) NOT NULL 
) 

INSERT INTO @Temp (PlacementId, PaymentTypeId, DateValue, Amount) 
SELECT 1, 5, '01-JAN-2015', 100 UNION 
SELECT 1, 5, '02-JAN-2015', 150 UNION 
SELECT 1, 5, '04-JAN-2015', 78 UNION 
SELECT 1, 5, '05-JAN-2015', 89 UNION 
SELECT 1, 5, '06-JAN-2015', 22 UNION 
SELECT 1, 10, '01-JAN-2015', 10 UNION 
SELECT 1, 10, '02-JAN-2015', 10 UNION 
SELECT 1, 10, '03-JAN-2015', 15 UNION 
SELECT 2, 5, '01-JAN-2015', 200 UNION 
SELECT 2, 5, '02-JAN-2015', 5 UNION 
SELECT 2, 5, '03-JAN-2015', 50 UNION 
SELECT 3, 5, '01-JAN-2015', 80 UNION 
SELECT 4, 5, '07-JAN-2015', 100 UNION 
SELECT 4, 5, '08-JAN-2015', 12 UNION 
SELECT 4, 5, '12-JAN-2015', 66 UNION 
SELECT 4, 5, '14-JAN-2015', 4 UNION 
SELECT 5, 10, '08-JAN-2015', 10 

SELECT * FROM @Temp 

SELECT 1 AS PlacementId, 5 AS PaymentTypeId, '2015-01-01' AS FromDate, '2015-01-02' AS ToDate, 250 AS Amount UNION 
SELECT 1, 10, '2015-01-01', '2015-01-03', 35 UNION 
SELECT 1, 5, '2015-01-04', '2015-01-06', 189 UNION 
SELECT 2, 5, '2015-01-01', '2015-01-03', 255 UNION 
SELECT 3, 5, '2015-01-01', '2015-01-01', 80 UNION 
SELECT 4, 5, '2015-01-07', '2015-01-08', 112 UNION 
SELECT 4, 5, '2015-01-12', '2015-01-12', 66 UNION 
SELECT 4, 5, '2015-01-14', '2015-01-14', 4 UNION 
SELECT 5, 10, '2015-01-08', '2015-01-08', 10 

Обратите внимание: есть NCI на PlacementID и PaymentTypeID.

Мы делаем это в настоящий момент с сумасшедшим грузом курсоров и имеем проблемы с высокой скоростью. (Для обработки 500 тыс. Линий требуется 4 минуты).

Есть ли эффективный метод для достижения желаемого результата?

+0

Да, правильно! Сожалею. Я исправлю это. – Craig

+0

Также для 'PlacementId = 1' и' PaymentTypeId = 10', если сумма будет равна '35',' 10 + 10 + 15'? –

ответ

2

Эта проблема называется Группировка островов сопредельных дат. Прочтите это article be Jeff Moden для получения дополнительной информации.

SQL Fiddle

;WITH Cte AS(
    SELECT *, 
     RN = DATEADD(DAY, - ROW_NUMBER() OVER(PARTITION BY PlacementId, PaymentTypeId ORDER BY DateValue), DateValue) 
    FROM @Temp 
) 
SELECT 
    PlacementId, 
    PaymentTypeId, 
    FromDate = MIN(DateValue), 
    ToDate = MAX(DateValue), 
    Amount = SUM(Amount) 
FROM Cte 
GROUP BY PlacementId, PaymentTypeId, RN 
ORDER BY PlacementId, PaymentTypeId, FromDate 
+0

@Craig, без проблем. Рад, что смог помочь. –

Смежные вопросы