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 が必要で、2 番目のサイクルで 10,20,50 が必要です。バケットが 4 の場合、最初は 10,20,40,50、2 番目は 10,20,40,50 です。

問題を表現するもう 1 つの方法は、新しいテーブルから最初の 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 に答える