0

在 SQL Server 中,我有一个 id 的源列表,我想以特定的方式重新排序以进行处理。我的原始表有一个 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
4

1 回答 1

1

好吧,我不知道 CTE 是否可行,因为有一些限制(不能top在递归部分使用,也不能在递归部分使用聚合)。
所以目前我得到了这个半周期:

更新

SQL 提琴示例

我稍微改变了一个查询,所以它不会一直计算在整个表中。我还从表中删除@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 提琴示例

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 
于 2012-10-28T17:59:34.427 回答