我有一个复杂的分组问题。我应该在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的记录组 详情:
样本数据分组说明:
第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。