SQL - 按N美元金额分组记录

时间:2012-08-14 17:51:31

标签: sql-server grouping aggregation

我的问题与

有些相似

Group by every N records in T-SQL

但是我想按最高金额分组

所以我有20条记录,总共amount为50,000,我需要将它们分组,以便每组最多可达10,000个。

我尝试使用一个运行值,给记录一个排名,然后将值< =当前排名相加,然后使用Floor((RunningValue - amount) / 10000)将它们分成子组,但有些情况下它会超过10,000最大值

示例数据,您可以在此处看到SubGroup 1超过10,000

SubGroupNo  RowNo   amount  RunningValue
0           1       790.5   790.5
0           2       790.5   1581
0           3       790.5   2371.5
0           4       790.5   3162
0           5       744     3906
0           6       744     4650
0           7       1348.5  5998.5
0           8       1348.5  7347
0           9       1348.5  8695.5
1           10      1348.5  10044
1           11      1302    11346
1           12      1302    12648
1           13      1302    13950
1           14      1302    15252
1           15      1255.5  16507.5
1           16      1209    17716.5
1           17      1116    18832.5
1           18      1116    19948.5
2           19      1302    21250.5
2           20      1302    22552.5
2           21      1302    23854.5
2           22      1255.5  25110
2           23      1255.5  26365.5
2           24      976.5   27342

1 个答案:

答案 0 :(得分:2)

这可能不是最好的方法,但它有效。它假定您的RowNo是连续的。如果没有,我会在此解决方案中添加ROW_NUMBER()

基于迭代的方法

SQL Fiddle

DECLARE @runningTotal decimal(7,2), @sgn tinyint, @cursor int, @count int
SET @runningTotal = '0.00'
SET @sgn = 0
SET @cursor = 1
SELECT @count = COUNT(*) FROM tbl

WHILE @cursor <= @count
BEGIN
    SELECT @runningTotal = @runningTotal + amount FROM tbl WHERE RowNo = @cursor
    IF @runningTotal > 10000
        BEGIN
            SELECT @runningTotal = amount FROM dbo.tbl WHERE RowNo = @cursor
            SET @sgn = @sgn + 1
        END
    UPDATE tbl SET SubGroupNo = @sgn WHERE RowNo = @cursor
    SET @cursor = @cursor + 1
END

编辑1:基于游标的方法

SET NOCOUNT ON;

DECLARE @SubGroupNo tinyint, @RowNo smallint, 
    @amount decimal(8,2), @RunningTotal decimal(7,2)

SET @SubGroupNo = 0
SET @RunningTotal = '0.00'

DECLARE row_cursor CURSOR FOR
    SELECT RowNo, amount FROM dbo.tbl

OPEN row_cursor

FETCH NEXT FROM row_cursor
INTO @RowNo, @amount

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @RunningTotal = @RunningTotal + @amount

    IF @RunningTotal > 10000
        BEGIN
            SET @RunningTotal = @amount
            SET @SubGroupNo = @SubGroupNo + 1
        END
    PRINT @RowNo 
    PRINT @RunningTotal
    PRINT @SubGroupNo

    UPDATE dbo.tbl SET SubGroupNo = @SubGroupNo WHERE RowNo = @RowNo

    FETCH NEXT FROM row_cursor
    INTO @RowNo, @amount
END

CLOSE row_cursor
DEALLOCATE row_cursor

结果

| SUBGROUPNO | ROWNO | AMOUNT | RUNNINGVALUE |
----------------------------------------------
|          0 |     1 |  790.5 |        790.5 |
|          0 |     2 |  790.5 |         1581 |
|          0 |     3 |  790.5 |       2371.5 |
|          0 |     4 |  790.5 |         3162 |
|          0 |     5 |    744 |         3906 |
|          0 |     6 |    744 |         4650 |
|          0 |     7 | 1348.5 |       5998.5 |
|          0 |     8 | 1348.5 |         7347 |
|          0 |     9 | 1348.5 |       8695.5 |
|          1 |    10 | 1348.5 |        10044 |
|          1 |    11 |   1302 |        11346 |
|          1 |    12 |   1302 |        12648 |
|          1 |    13 |   1302 |        13950 |
|          1 |    14 |   1302 |        15252 |
|          1 |    15 | 1255.5 |      16507.5 |
|          1 |    16 |   1209 |      17716.5 |
|          2 |    17 |   1116 |      18832.5 |
|          2 |    18 |   1116 |      19948.5 |
|          2 |    19 |   1302 |      21250.5 |
|          2 |    20 |   1302 |      22552.5 |
|          2 |    21 |   1302 |      23854.5 |
|          2 |    22 | 1255.5 |        25110 |
|          2 |    23 | 1255.5 |      26365.5 |
|          2 |    24 |  976.5 |        27342 |

模式

CREATE TABLE tbl (
  SubGroupNo tinyint,
  RowNo tinyint PRIMARY KEY,
  amount decimal(6,2),
  RunningValue decimal(7,2))

INSERT INTO tbl (RowNo, amount, RunningValue)
VALUES
(1, '790.5', '790.5'),
(2, '790.5', '1581'),
(3, '790.5', '2371.5'),
(4, '790.5', '3162'),
(5, '744', '3906'),
(6, '744', '4650'),
(7, '1348.5', '5998.5'),
(8, '1348.5', '7347'),
(9, '1348.5', '8695.5'),
(10, '1348.5', '10044'),
(11, '1302', '11346'),
(12, '1302', '12648'),
(13, '1302', '13950'),
(14, '1302', '15252'),
(15, '1255.5', '16507.5'),
(16, '1209', '17716.5'),
(17, '1116', '18832.5'),
(18, '1116', '19948.5'),
(19, '1302', '21250.5'),
(20, '1302', '22552.5'),
(21, '1302', '23854.5'),
(22, '1255.5', '25110'),
(23, '1255.5', '26365.5'),
(24, '976.5', '27342')