Ö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
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..
Mükemmel Bir Kaynak. Çok Teşekkür Ederim.