Sql server中组合的复杂分组算法

时间:2016-08-23 16:48:09

标签: sql-server algorithm grouping combinations

我有一个复杂的分组问题。我应该在Sql server 2005上解决它,但是一个适用于更新版本的解决方案是可以的(我们很快就会升级)。

测试表:

CREATE TABLE [dbo].[testGrouping](
[Family] [varchar](50) NOT NULL,
[Person] [varchar](50) NOT NULL,
[transNr] [int] NOT NULL,
[Amount] [numeric](6, 2) NOT NULL,
[ExpectedGroup] [int] NULL
    )       

测试数据

INSERT INTO [testGrouping]([Family],[Person],[transNr],[Amount],[ExpectedGroup])
SELECT       'f1','p1',1,  10.00,1
union SELECT 'f1','p1',2 , -9.00,1
union SELECT 'f1','p2',3 , -1.00,1
union SELECT 'f2','p3',4 , 50.00,2
union SELECT 'f2','p4',5 ,-50.01,2
union SELECT 'f2','p5',6 ,-30.00,3
union SELECT 'f2','p5',7 , 20.00,3
union SELECT 'f2','p5',8 , 10.00,3
union SELECT 'f3','p7',9 , -1.00,4
union SELECT 'f3','p7',10, -2.00,4
union SELECT 'f3','p7',11, -6.00,null
union SELECT 'f3','p9',12,  2.00,null
union SELECT 'f3','p7',13,  3.00,4
union SELECT 'f2','p6',14,100.00,null

现在问题。 ExpectedGroup从null开始,我必须用我的代码填充它。

要求是识别具有ABS(总和(金额))<= 0.01的记录组 详情:

  • 我可以将同一个“人”的2条或更多条记录分组;
  • 经过人员分组后,我可以在同一个“家庭”中搜索群组
  • 每条记录只能属于1组
  • 每个人只能属于1个家庭
  • 无法分组的记录具有group = null
  • 一个群组可以有超过2条记录(这是真正的挑战!)
  • 在实际数据中,每个“家庭”最多可以有200条记录,每个“人”最多可以有10条记录。
  • 金额始终为&lt;&gt; 0

样本数据分组说明:

  • 第1组: 包括家庭f1的所有记录,因为该家庭中没有人的部分组合具有ABS(总和(金额))&lt; = 0.01

  • 第2组: 人p3和p4具有ABS(总和(量))<= 0.01。

  • 第3组: 人p5具有ABS(总和(量))<= 0.01。所以家庭f2分为2组,单个记录(transNr 13)没有组

  • 第4组: 在f3族中,您可以对transNr 9和11进行分组,但是只有一个属于Person p7的组,因此它具有更高的优先级。

我可以很容易地找到像第1组这样的群组

select family, sum(amount) from testGrouping group by Family HAVING ABS(sum(amount)) <= 0.01

以及第3组

select person, sum(amount) from testGrouping group by Person HAVING ABS(sum(amount)) <= 0.01

但是其他案例都很棘手(参见Family f2:有几种方法可以在那里构建组,按p5分组是微不足道的,但其他记录并不那么容易)

我在伪代码中的想法是:

-- process the easy cases...
group by person, set a group number to persons having ABS(sum(amount)) <= 0.01
group by family, set a group number to families having ABS(sum(amount)) <= 0.01 

-- process the remaining records
For each person
  Generate all combinations of not grouped records of that person 
  For each combination of records
    IF ABS(sum(amount)) of the combination <= 0.01 THEN
       Assign a group to records of the combination
       Recalculate the combinations (we have less records to work with)
    END IF
  Next combination
Next person

For each family
  Generate all combinations of not grouped records of that family 
  For each combination of records
    IF ABS(sum(amount)) of the combination <= 0.01 THEN
       Assign a group to records of the combination
       Recalculate the combinations (we have less records to work with)
    END IF
  Next combination
Next family

(on each step I can use only record not assigned to a group in previous steps, the For each translates into cursors)

我的问题是:

  • 你能建议我一个更好的算法吗? (解决方案必须只是SQL,但要描述它伪代码是好的)我认为我的伪代码转换为嵌套循环,游标,goto和其他丑陋代码的意大利面条代码。(性能不是那么关键,几分钟就可以处理了可以接受10.000条记录)

  • 如何实施“生成所有组合”部分?在样本中,对于F2家庭,我应该尝试所有可能的2个记录组,然后是所有可能的3个组,依此类推,直到测试所有组合。 transNr是唯一的记录ID。

0 个答案:

没有答案