按条件对行进行分组

Group rows by condition

我有这个数据:

Start   End     Quantity
425     449     24
450     474     24
475     499     24
500     524     24
2300    2324    24
2400    2499    99
2500    2599    99
2800    2899    99
2900    2999    99
3200    3249    49
3250    3299    49
3300    3349    49
3350    3399    49
3400    3449    49
3500    3549    49
3600    3624    24
3650    3674    24
3700    3724    24
3950    3964    14
4000    4000    0
4150    4399    249
4400    4499    99
5034    5075    41

数量是 End - Start 的结果。

我想获取以下数据,第 Generated 行:

Start   End     Quantity
425     449     24
450     474     24
475     499     24
500     524     24
425     524     96
2300    2324    24
2300    2324    24
2400    2499    99
2500    2599    99
-----GENERATED----
425     2599    438
------------------

2800    2899    99
2900    2999    99
3200    3249    49
3250    3299    49
3300    3349    49
3350    3399    49
3400    3449    49
3500    3549    49
-----GENERATED-----
2800    3549    492
------------------

3600    3624    24
3650    3674    24
3700    3724    24
3950    3964    14
4000    4000    0
4150    4399    249
4400    4499    99
5034    5075    41
-----GENERATED-----
3600    5075    475
------------------

条件是它必须将所有数量加起来直到 500。如果超过 500,则重新计数。

我尝试过使用 Rollup,但找不到合适的条件让它工作。

当然,通过编程代码比SQL更容易做到这一点,但我们必须在数据库环境中进行。获取生成行的工具可以是任何东西,循环函数,新表等。

错误解决

我在 运行 @Prdp 的查询时遇到错误:

Msg 530, Level 16, State 1, Line 1
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.

我在这里找到了解决方案: http://sqlhints.com/tag/the-statement-terminated-the-maximum-recursion-100-has-been-exhausted-before-statement-completion/

更新 1

使用@Prdp 的查询我们得到了以下信息:

Start   End     rn  st
(400)   424     1   24
425     449     2   48
450     474     3   72
475     499     4   96
500     524     5   120
2300    2324    6   144
2400    2499    7   243
2500    2599    8   342
2800    (2899)  9   (441)  
(2900)  2999    10  99
3200    3249    11  148
3250    3299    12  197
3300    3349    13  246
3350    3399    14  295
3400    3449    15  344
3500    3549    16  393
3600    3624    17  417
3650    3674    18  441
3700    3724    19  465
3950    3964    20  479
4000    (4000)  21  (479) 
(4150)  4399    22  249
4400    4499    23  348
5034    (5075)  24  (389) 

它越来越接近我们需要的了。是否可以仅提取 () 之间的数据而丢弃其他数据? 我们也可以使用游标。

您可以使用 Recursive CTE。我想不出更好的方法。

;WITH cte
     AS (SELECT *,
                Row_number()OVER(ORDER BY start) rn
         FROM   Yourtable),
     rec_cte
     AS (SELECT *,
                ( [End] - Start ) AS st,
                1                 AS grp
         FROM   cte
         WHERE  rn = 1
         UNION ALL
         SELECT a.*,
                CASE
                  WHEN st + ( a.[End] - a.Start ) >= 500 THEN a.[End] - a.Start
                  ELSE st + ( a.[End] - a.Start )
                END,
                CASE
                  WHEN st + ( a.[End] - a.Start ) >= 500 THEN b.grp + 1
                  ELSE grp
                END
         FROM   cte a
                JOIN rec_cte b
                  ON a.rn = b.rn + 1)
SELECT Min(Start) as Start,
       Max([End]) as [End],
       Max(st) as Quantity
FROM   rec_cte
GROUP  BY grp
OPTION (maxrecursion 0) 

这是 MySQL 中提出的解决方案。类似的策略应该适用于 SQL 服务器。

drop table if exists TestData;
create table TestData(Start int, End int, Quantity int);
insert TestData values (425,449,24);
insert TestData values (450,474,24);
insert TestData values (475,499,24);
insert TestData values (500,524,24);
insert TestData values (2300,2324,24);
insert TestData values (2400,2499,99);
insert TestData values (2500,2599,99);
insert TestData values (2800,2899,99);
insert TestData values (2900,2999,99);
insert TestData values (3200,3249,49);
insert TestData values (3250,3299,49);
insert TestData values (3300,3349,49);
insert TestData values (3350,3399,49);
insert TestData values (3400,3449,49);
insert TestData values (3500,3549,49);
insert TestData values (3600,3624,24);
insert TestData values (3650,3674,24);
insert TestData values (3700,3724,24);
insert TestData values (3950,3964,14);
insert TestData values (4000,4000,0);
insert TestData values (4150,4399,249);
insert TestData values (4400,4499,99);
insert TestData values (5034,5075,41);

drop table if exists DataRange;
create table DataRange (StartRange int, EndRange int);
insert DataRange values (425, 2599);
insert DataRange values (2800,3549);
insert DataRange values (3600,5075);

select
DataRange.StartRange,DataRange.EndRange
,sum(TestData.quantity) as Quantity 
from TestData 
inner join DataRange on 
    (TestData.start between DataRange.StartRange and DataRange.EndRange )
    or
    (TestData.End between DataRange.StartRange and DataRange.EndRange )
group by DataRange.StartRange,DataRange.EndRange