A cursor is used, but it’s slow and appears to be a big bottleneck in a SQL job. Basically, this is a cleanup effort to remove all but the top X accessories (ordered by sales rank) from a particular source that’s previously grouped by a product id and account visibility.
The command is basically built in the each iteration of the cursor loop and exec‘ed manually.
The vis column refers to multiple tenants that sort of acts like a bitmask e.g. two tenants could have the same product.
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
Sample output could look like
prodid cnt vis
123 6 128
234 8 260
345 10 512
In the case where X=5, the last 1 salesrank item for 123 would be removed, the last 3 for 234 and the last 5 for 345. Can this be done using a DELETE statement while including the groupings in some nested select?
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
Try this: