获取分组为一行

时间:2015-06-10 23:53:48

标签: sql-server sql-server-2008

我有一张桌子可以容纳很多行(目前,500K,预计在未来3年内会增加到1500万)。该表格包含特定日期特定活动的付款。事件可以在同一天支付一次或多次,但同一天的付款必须具有不同的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

请注意,PlacementID和PaymentTypeID上有NCI。

我们现在正在用疯狂的游标加载,并且正在进行极端的速度问题。 (500K线需要4分钟才能处理完毕。)

是否有一种有效的方法来实现所需的输出?

1 个答案:

答案 0 :(得分:2)

这是一个名为分组连续日期的问题。请阅读此article作为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