2012-07-10 79 views
1

使用遊標,但速度很慢,似乎是SQL作業中的一大瓶頸。基本上,這是一項清理工作,可以從以前按產品ID和帳戶可見性分組的特定源中移除除頂級X附件(按銷售排序排序)以外的所有附件。SQL按條件刪除組

該命令基本上是在遊標循環和exec'手動每次迭代中構建的。

vis列指的是多個租戶,其類似於位掩碼等行爲。兩個租戶可以擁有相同的產品。

declare @prodid int 
declare @cnt int 
declare @vis bigint 
declare @cmd varchar(600) 
declare @clause varchar(600) 

-- find records with more than X excess accessories 
declare cur cursor for 
    select pa.prodid, 'cnt' = count(*), vis from [accessories] pa 
    group by prodid, vis 
    having count(*) > X -- e.g. 5 

示例輸出可能看起來像

prodid cnt  vis 
123  6  128 
234  8  260 
345  10  512 

在X = 5時,爲123最後1 salesrank項目將被刪除的情況下,在最後3爲234和最後5爲345。 這可以使用DELETE語句完成,而在某些嵌套選擇中包含分組?

open cur 

fetch next from cur into @prodid, @cnt, @vis 
while @@fetch_status = 0 
begin 
    -- a clause that ends up looking like this: 
    -- 12345 and vis = 128 -- OR -- 23456 and vis is null 
    set @clause = convert(varchar(14), @prodid) + ' and vis ' + case 
     when @vis is null then ' is null ' 
     else ' = ' + cast(@vis as varchar) end 

    -- delete all but the top X from source=2 and that match prodid and vis 
    set @cmd = 'delete from [accessories] 
     where source = 2 and prodid=' + @clause + 
     ' and access_prodid in (select top ' + convert(varchar(5), @cnt - X) + 
     ' access_prodid from [accessories] where prodid = ' 
     + @clause + ' and source = 2 order by salesrank)' 

    exec(@cmd) 
    fetch next from cur into @prodid, @cnt, @vis 
end 
close cur 
deallocate cur 

回答

4

試試這個:

WITH DupData AS 
(
    SELECT *, 
     ROW_NUMBER() 
      OVER(PARTITION BY pa.prodid, pa.vis ORDER BY salesrank) Position 
     FROM [accessories] pa 
     WHERE pa.source = 2 
) 
DELETE 
    FROM DupData 
WHERE Position > 5 
0

我會做到這一點,通過使用Windows API函數來確定的行被刪除:

with t as (select pa.*, 
        row_number() over (partition by prodid, vis order b salesrank) as sr 
      from [accessories] pa 
     ) 
delete from pa 
from t 
where pa.prodid = t.prodid and pa.vis = t.vis and pa.salesrank = t.salesrank 

如果在每年的唯一ID表,那麼你可以使用它來代替更復雜的where語句。這假定salesrank在每個prodid/vis組內都是唯一的。