2012-10-28 45 views
0

在SQL Server分发列表桶我的ID,我想重新排序在处理特定方式的源列表。我原来的表有像10,10,10,10,10,20,20,20,20,30,40,40,50,50,60 ID和与之关联的唯一密钥列表。他们可以以任何顺序。我想通过窗口或循环将它们分发到桶中,以便它们不会发生冲突。我对聚合函数很熟悉,我在数学上遇到了麻烦,无法将其分发。我可以做一个循环,但出于性能方面的原因,如果可能的话,我希望在单个查询中完成。通过窗口或循环处理

我有一个查询获得计数和优先喜欢

Count Id Priority 
5  10 1 
4  20 2 
2  40 3 
2  50 4 
1  30 5 
1  60 6 

桶的#是任意的,虽然决定的时间提前。如果是3,我想在第一个周期中id为10,20,40,然后在第二个周期中为10,20,50。如果桶是4,那么首先是10,20,40,50,再次是10,20,40,50。

我表达这个问题的另一种方法是我想通过计数来自新表抢了先X,递减计数,然后抢在下一个X,直到筋疲力尽。

接过解决方案建议,并重新写的,但我仍然在寻找可能的话单个SQL查询的解决方案。

我已经更新了建议循环的位上应该有一点更加优化尚未将其更新到我的实际工作量

declare @bucket int, @b int, @maxrows int 
declare @buckets table (fstrEntityHash varchar(100), bucket int) 
declare @count table (flngCount int, fstrEntityHash varchar(100)) 
declare @bucketTemp table (fstrEntityHash varchar(100), bucket int) 

select @bucket = 3, @maxrows = 20 

insert into @count 
select COUNT(1) as flngCount, 
    fstrEntityHash 
from tblTest 
group by fstrEntityHash 
order by COUNT(1) desc 

set @b = 1 
while (1 = 1) 
begin 
insert into @bucketTemp 
select top (@bucket) fstrEntityHash, @b 
from @count 
where flngCount > 0 
order by flngCount desc; 

if @@rowcount = 0 
    break 

update C 
set C.flngCount -= 1 
from @count C, @bucketTemp I 
where C.fstrEntityHash = I.fstrEntityHash 

insert into @buckets 
select * 
from  @bucketTemp 

if (select count(1) from @buckets) >= @maxrows 
    break 

select @b = @b + 1 
delete from @bucketTemp 

end 

select * from @buckets 

回答

1

好吧,我不知道这是否是可能的CTE,原因有一些限制(你不能在递归部分使用top和递归部分不能使用聚合)。因此,对于当下
我得到这个半周期:

UPDATE

SQL FIDDLE EXAMPLE

我已经改变了查询一点点,所以它不会遍数表的所有倍。我也是从表@counts删除所有不必要的记录和计算最小优先级与我能得到记录。

declare @bucket int, @b int, @Priority int 
declare @buckets table (Id int, bucket int) 
declare @bucketsTemp table (Id int primary key, [Count] int, Priority int) 
declare @counts table (Id int primary key, [Count] int, Priority int) 

select @bucket = 3, @b = 1 
select @Priority = min(Priority) from temp 

while (1 = 1) 
begin 
    insert into @bucketsTemp (Id, [Count], Priority) 
    select top (@bucket) 
     t.Id, 
     isnull(c.[Count], t.[Count]) - 1 as [Count], 
     t.Priority 
    from temp as t 
     left outer join @counts as c on c.Id = t.Id 
    where t.Priority >= @Priority and isnull(c.[Count], t.[Count]) > 0 
    order by t.Priority 

    if @@rowcount = 0 
     break 

    insert into @buckets 
    select b.Id, @b 
    from @bucketsTemp as b 

    update @counts set 
     c.[Count] = b.[Count] 
    from @counts as c 
     inner join @bucketsTemp as b on b.Id = c.Id 

    insert into @counts 
    select b.Id, b.[Count], b.Priority 
    from @bucketsTemp as b 
    where b.Id not in (select c.Id from @counts as c) 

    delete @counts 
    from @counts as c 
    where 
     c.[Count] = 0 and 
     not exists (select * from @counts as t where t.Priority < c.Priority and t.[Count] <> 0) 

    delete from @bucketsTemp 

    select @Priority = min(Priority) from @counts 
    select @b = @b + 1 
end 

select * from @buckets 

首先尝试是

SQL FIDDLE EXAMPLE

declare @bucket int, @b int 
declare @buckets table (Id int, bucket int) 

select @bucket = 3, @b = 1 

while (1 = 1) 
begin 
    insert into @buckets 
    select top (@bucket) 
    t.Id, 
    @b 
    from <your table> as t 
    left outer join 
    (
     select t.Id, count(*) as [Count] 
     from @buckets as t 
     group by t.Id 
    ) as B on B.Id = t.Id 
    where t.[Count] - isnull(B.[Count], 0) > 0 
    order by t.Priority asc 

    if @@rowcount = 0 
    break 

    select @b = @b + 1 
end 

select * from @buckets 
+0

谢谢,但我希望为单个查询解决方案,因为我原来我有几百万或ID的。我会试试看,但看到。 – user417639

+0

对于数百万用户,您需要优化解决方案。后来我将修改我的职务,IHAVE一双想法,但没有时间,现在 –

+0

我已经更新了查询了一下这应该是一个多一点的优化还没有肯定的更新,以我添加了我的真实工作量 – user417639