日期:2014-05-18  浏览次数:20826 次

Sql 按指定重量进行分组问题
表结构如下: tb1
ID OrderID Weight AutoID TotalWeight GroupID 
3339 12800389 0.023800 1 0.023800
3339 12800272 0.045000 2 0.068800
3339 12800267 0.133000 3 0.201800
3339 12800254 0.750000 4 0.951800
3339 12800344 0.365000 5 1.316800
3339 12800315 0.047000 6 1.363800
3339 12800298 0.137000 7 1.500800
3339 12794841 0.765000 8 2.265800
3339 12794837 0.765000 9 3.030800
3339 12786045 0.865600 10 3.896400
3339 12786042 0.865600 11 4.762000
3339 12800679 0.033200 12 4.795200
3339 12800677 0.035100 13 4.830300
3339 12800633 0.057700 14 4.888000
3339 12800602 0.027000 15 4.915000
……

说明:AutoID 为自动生成
  GroupID 为分组编号

现在 sum(Weight) 以1.5为倍数修改GroupID列
select GroupID,Sum(Weight) as GroupWeight from tb1 group by GroupID 
使得这里面的 GroupWeight<=1.5 成立

我写了如下SQL来实现,在数据少的情况下是正确的,数据一多就出现问题了

SELECT *, ( SELECT SUM(Weight)
  FROM tb1 t2
  WHERE [t2].[AutoID] <= [t1].[AutoID]
  AND [t2].[ID] = [t1].[ID]
  ) AS totalweight,
  Cast(( ( SELECT SUM(Weight)
  FROM tb1 t2
  WHERE [t2].[AutoID] <= [t1].[AutoID]
  AND [t2].[id] = [t1].[id]
  ) / 1.5 as int ) AS diffid
 FROM tb1 t1
因为数据量一多,除完取整的话存在一定的误差,使得上面的GroupWeight>1.5







------解决方案--------------------
你的意思我是看明白了,但暂时没有想到集合解决的思路,只能临时用游标解决了,看看你的数据量大不大,不大,速度能够接受的话,你可以试试。
你的方法里面用累计求和除以1.5,这个方法本身有问题,与精度是没有关系的。
就是说下一个分组的值会分摊到上个分组中,这样你除出来可能没有超过1.5,但是实际已经超过了,
里面 AutoID =9,Weight= 0.765 ;AutoID =10,Weight= 0.8656 就是我上面说的情况,被你分组到一个组里面去了。
SQL code
IF OBJECT_ID('tb1') IS NOT NULL
  DROP TABLE tb1
GO
CREATE TABLE tb1(ID int, OrderID varchar(10), Weight numeric(18, 6), AutoID int, 
                TotalWeight numeric(18,6), GroupID int);
GO
INSERT INTO tb1(ID, OrderID, Weight, AutoID, TotalWeight)
SELECT 3339, '12800389',  0.0238,  1,  0.0238 UNION ALL
SELECT 3339, '12800272',  0.045,  2,  0.0688 UNION ALL
SELECT 3339, '12800267',  0.133,  3,  0.2018 UNION ALL
SELECT 3339, '12800254',  0.75,  4,  0.9518 UNION ALL
SELECT 3339, '12800344',  0.365,  5,  1.3168 UNION ALL
SELECT 3339, '12800315',  0.047,  6,  1.3638 UNION ALL
SELECT 3339, '12800298',  0.137,  7,  1.5008 UNION ALL
SELECT 3339, '12794841',  0.765,  8,  2.2658 UNION ALL
SELECT 3339, '12794837',  0.765,  9,  3.0308 UNION ALL
SELECT 3339, '12786045',  0.8656,  10,  3.8964 UNION ALL
SELECT 3339, '12786042',  0.8656,  11,  4.762 UNION ALL
SELECT 3339, '12800679',  0.0332,  12,  4.7952 UNION ALL
SELECT 3339, '12800677',  0.0351,  13,  4.8303 UNION ALL
SELECT 3339, '12800633',  0.0577,  14,  4.888 UNION ALL
SELECT 3339, '12800602',  0.027,  15,  4.915;

--*****************************************************
--利用游标解决
declare @aID int, @wei numeric(18,6);
declare @GroupID int;
declare @sumWeight numeric(18,6);
declare @tmpT table(AutoID int, GroupID int);
set @sumWeight = 0;
set @GroupID = 0;

declare C CURSOR fast_forward for select AutoID, [Weight] from tb1 order by AutoID;
open C
fetch Next From C into @aID, @wei;
while @@FETCH_STATUS = 0
begin
    set @sumWeight = @sumWeight + @wei;
    if @sumWeight > 1.5
    begin
        set @GroupID = @GroupID + 1;
        insert into @tmpT(AutoID, GroupID) Values(@aID, @GroupID);
        set @sumWeight = @wei;
    end
    else begin
        insert into @tmpT(AutoID, GroupID) Values(@aID, @GroupID);
    end
    fetch Next From C into @aID, @wei;
end
Close C;
Deallocate C;
--更新原表的GroupID数据
update a
set a.GroupID = b.GroupID
from tb1 a
    join @tmpT b
    on a.AutoID = b.AutoID;

select * from Tb1;    

/*
ID          OrderID    Weight     Auto