【问题标题】:SQL - Group records by N dollar amountSQL - 按 N 美元金额对记录进行分组
【发布时间】:2012-08-11 01:50:15
【问题描述】:

我的问题有点类似于

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

【问题讨论】:

  • 那是knapsack problem,最好在SQL之外解决
  • 有点,但记录必须保留在其RowNo 顺序中

标签: sql-server grouping aggregation


【解决方案1】:

这可能不是最好的方法,但它确实有效。它假定您的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

结果

|子组号 |罗诺 |数量 |运行价值 | ---------------------------------------------- | 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')

【讨论】:

  • SubGroupNo 1 仍然超过 10k
  • 这与我的做法非常接近,除了细微的差别(WHILE 而不是 CURSOR)。我希望找到一种更简洁的方法,而无需遍历每条记录,但这可能是唯一的方法
  • @msmucker0527 我认为 CURSOR 方法可能更干净。抱歉,我无法提供更多帮助。
猜你喜欢
  • 2015-01-03
  • 1970-01-01
  • 2021-09-01
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 1970-01-01
  • 2020-05-23
相关资源
最近更新 更多