views:

627

answers:

6
+1  Q: 

SQL delete loop

I have a table of housing listings. I would like to keep a maximum of 10 listings per city. (Most cities have less than 10 listings).

When I do this query:

 select city, count(city) as cityCount from tREaltyTrac group by city

SQL returns:

Acampo  1
Acton   1
Adelanto    20
Agua Dulce  1
Aguanga 1
Akron   19
Albany  12
Albion  3
Alexandria  14
Algonac 1
Alhambra    5

So Adelanto, Akron, Albany, and Alexandria must be cut back to only 10 listings ordered by most recent datetime field called 'creation' (order by creation desc).

Can anyone think of a procedure that will cut the listings back as described?

A: 

you shouldn't delete records out of a database. this isn't 100% perfect and i'm sure there are better ways to do it, but here ya go.

declare @cities (CityName nvarchar(50), ID int identity(1,1))
declare @returns (CityName nvarchar(50), Blah nvarchar(50))
declare @cityname nvarchar(50)
declare @count int
declare @i int


insert into @cities (CityName)
select distinct CityName
from tblCities

select @count = count(*) from @cities
set @i=1

while (@i<=@count)
begin

    select @cityname = CityName from @cities where ID=@i

    select top 10 *
    from tblCities
    where CityName=@cityname
    order by Creation desc

    set @i=@i+1
end
DForck42
+1 for advising not to delete records
Nathan Koop
looping is very slow, there are ways to do this in a single statement, see my answer
KM
yeah, i figured there was a better way to do it, i just couldn't think of it at the time. that's why i made it a part of my comment.
DForck42
A: 

I haven't got time to write out the actual code right now, but how about something like this.... (assumes PHP)

  1. Order your initial query - add creation DESC
  2. Loop through results, and get the creation date of the 10th result
  3. Run another query that deletes everything less than the creation value for the 10th result? - i.e. DELETE WHERE Creation < $creationDateOfTenthResult

Hope that makes sense...

Matt
Another possible solution... instead of using the date, have a unique ID field, and then your delete query could be DELETE WHERE uniqueID < $uniqueIDOfTenthResult.
Matt
PHP? I hope you don't fetch all the rows and loop through them in PHP and then delete from there. looping is very slow, there are ways to do this in a single SQL statement, see my answer
KM
Thanks - I just learned something!
Matt
A: 

I would select the top ten, throw them in a temp table, delete the original and populate it with the temp table.

Ichorus
+1  A: 

Something like this should take care of it for you, but deleting records automatically isn't a great idea. You'd be better off using an active flag.

DECLARE @CityName VARCHAR(30)
DECLARE CitiesOver10 CURSOR FOR select city from tREaltyTrac group by city having count(city)>10 

OPEN CitiesOver10
FETCH NEXT FROM CitiesOver10 INTO @CityName

WHILE @@FETCH_STATUS = 0
    BEGIN
     DELETE FROM 
      dbo.tREaltyTrac 
     WHERE 
      ID NOT IN (SELECT TOP 10 ID FROM dbo.tREaltyTrac WHERE city = @CityName ORDER BY Creation DESC)
      AND City = @CityName

     FETCH NEXT FROM CitiesOver10 INTO @CityName
    END

CLOSE CitiesOver10
DEALLOCATE CitiesOver10
jblaske
-1 - avoid CURSORS like the plague! There are smarter ways to do this.
marc_s
cursor loops are very slow, there are usually ways to use a single statement, see my answer
KM
A: 

Depends on your version of sql. Something similar to this might work

SELECT r.City, b.* FROM tREaltyTrac r join tREaltyTrac b on b.Id in ( select top 10 Id from tREaltyTrac where Id = r.Id order by Id Desc ) group by r.City

Jay
+4  A: 

DON'T LOOP!

I prefer marking th rows with a status, but this will do as you want and delete them...

try this (sql server)

set up table

create table tREaltyTrac (city varchar(20),creation datetime)
insert into tREaltyTrac values ('Acampo'      ,getdate()) --1
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Acton'       ,getdate()) --1
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Adelanto'    ,getdate()) --20
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Agua Dulce'  ,getdate()) --1
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Aguanga'     ,getdate()) --1
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Akron'       ,getdate()) --19
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albany'      ,getdate()) --12
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albion'      ,getdate()) --3
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albion'      ,getdate()) --3
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Albion'      ,getdate()) --3
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alexandria'  ,getdate()) --14
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Algonac'     ,getdate()) --1
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alhambra'    ,getdate()) --5
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alhambra'    ,getdate()) --5
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alhambra'    ,getdate()) --5
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alhambra'    ,getdate()) --5
waitfor delay '00:00:01'
insert into tREaltyTrac values ('Alhambra'    ,getdate()) --5

display table values

select city,count(*) from tREaltyTrac group by city
select * from tREaltyTrac

delete the rows you don't want

delete from tREaltyTrac
    from tREaltyTrac
        inner join (select
                        city,creation, row_number() over(partition by city order by city) AS RankValue
                        from tREaltyTrac
                   ) dt on tREaltyTrac.city=dt.city AND tREaltyTrac.creation=dt.creation
    where dt. RankValue>10

show the rows you have left

select * from tREaltyTrac
select city,count(*) from tREaltyTrac group by city
KM
the inserts run with 1 second delays each, so the times would be different so you could tell that the oldest ones were the ones that were deleted
KM
Nice! In other less-capable SQL engines you might be well advise to make a temporary table for what apparently SQL Server handles well as a nested select (and unfortunately not all engines yet support the sql'03 standard "row_number() over(partition", sigh).
Alex Martelli
+1 for using the ROW_NUMBER() ranking function! I was working on two CTE's using the same approach, but you beat me to the punch :-)
marc_s