Önceki yazıda mükerrer eden kayıtları sahip oldukları identity deÄŸeri sayesinde silebiliyorduk. Peki Sql Server’daki bu tabloda kayıtları birbirinden ayıracak herhangi bir Primary Key veya Unique Constraint yoksa kayıtları nasıl sileceÄŸiz. L_User isimli tablosunda kayıtları ÅŸu ÅŸekilde durduÄŸunu varsayalım.

Key column information is insufficient or incorrect. Too many rows were affected by update
hatasıyla karşılaşırız. Bu tür kayıtları SEM içerisinde değil Query Analyzer aracılığıyla silebiliriz.
DELETE FROM L_User WHERE UserName='ahmet' AND UserPwd='123'
Bu durumda kullanıcı adı, “Ahmet”, ÅŸifresi,”123″ olan tüm kayıtları silmiÅŸ oluruz. Oysa amacımız tekrar eden kayıtların tümünü silmek deÄŸil o kayıtları bire indirgemektir.
Böyle bir durum için en kısa çözüm, geçici(temporary) bir tablo kullanarak asıl tabloyu yeniden oluşturmaktır. Önce, satırları, tekrar eden kolonlarına göre gruplayıp geçici bir tabloya aktaracağız. Daha sonra asıl tabloyu silip geçici tabloyu, asıl tabloya aktaracağız.
--Kayıtları grupla ve T isimli geçici tabloya yükle SELECT * INTO #T FROM L_User GROUP BY UserName,UserPwd /* VEYA gruplama yerine DISTINCT kullanılabilir SELECT DISTINCT UserName,UserPwd INTO #T FROM L_User1 */ --Asıl tablodaki kayıtları sil DELETE L_User --#T tablosunu asıl tabloya aktar INSERT INTO L_User SELECT * FROM #T
| UserName | UserPwd |
|---|---|
| adem | 789 |
| ahmet | 123 |
| mehmet | 456 |
Tabi kayıtların bu şekilde databasede tutulması pek mantıklı bir yaklaşım olmadığı için bunlara identity kazandırmak daha doğru olacaktır. Bu durumda verileri geçici tabloya aktarırken identity kolon da oluşturulabiliriz.
--Kayıtları grupla ve T isimli geçici tabloya yükle SELECT ColumnId=IDENTITY(int,1,1),UserName,UserPwd INTO #T FROM L_User GROUP BY UserName,UserPwd --Asıl tabloyu drop edelim DROP TABLE L_User --#T tablosunu L_User isimli bir tabloya kopyalayalım. SELECT * INTO L_User FROM #T
| ColumnId | UserName | UserPwd |
|---|---|---|
| 1 | adem | 789 |
| 2 | ahmet | 123 |
| 3 | mehmet | 456 |
SQL Server 2005‘te mükerrer kayıtları silmeyi aynı mantıkla yapabileceÄŸimiz gibi kendisinin sunmuÅŸ olduÄŸu ROW_NUMBER() fonksiyonundan yararlanılabilir. Bu fonksiyon, SELECT anında belirlediÄŸimiz argümanlara göre kolonları numaralandırır. ROW_NUMBER() fonksiyonu, PARTITION sözcüğüyle kullanıldığı zaman parametre olarak aldığı kolonların deÄŸerine göre parçalı sıralama yapar. Yani aynı kayıtları kendi içerisinde gruplandırarak ardışık numaralandırır. DiÄŸer farklı kayda geçtiÄŸi zaman yeniden 1′den baÅŸlayarak numaralandırır. Bu ÅŸekilde satırları numaralandırdıktan sonra araya ikinci bir tablo atmamak için de yine SQL 2005′in önemli özelliklerinden biri olan Common Table Expression(CTE) yöntemini kullanacağız. CTE, bir tabloyu yeniden tanımlamak ve bu tanımlayı referans alacak bir querynin çalıştırılmasıdır. Özellikle bir tablo üzerindeki yinelemeli iÅŸlemlerde kullanılır.
SELECT ROW_NUMBER() OVER (ORDER BY UserName ASC) AS ColumnId, * FROM L_User
| TekraraBagliId | UserName | UserPwd |
|---|---|---|
| 1 | adem | 789 |
| 2 | adem | 789 |
| 1 | ahmet | 123 |
| 2 | ahmet | 123 |
| 1 | mehmet | 456 |
Bu ifadeyi CTE ile birlikte kullanalım. Yapacağımız iÅŸlem basit; TekraraBagliId kolonu 1′den büyük olanları sileceÄŸiz.
WITH TekrarliKayit AS ( SELECT ROW_NUMBER() OVER ( PARTITION BY UserName,UserPwd ORDER BY UserName ASC) AS TekraraBagliId, * FROM L_User ) DELETE FROM TekrarliKayit WHERE TekraraBagliId>1




AÄŸustos 28th, 2007 at 11:55
Ahmet Kaymaz Bey..
Tek kelime ile süpersiniz.Geçenlerde bu problemi aynen yaşamışdım.Harika bir makale..ellerinize sağlık..1000 ler selam..
AÄŸustos 29th, 2008 at 04:28
Mükemmel Bir Kaynak. Çok Teşekkür Ederim.