SQL ROW_NUMBER, RANK ve DENSE_RANK Farkı
ROW_NUMBER, RANK ve DENSE_RANK satırlara sıralama numarası veren SQL window function’larıdır. Aralarındaki temel fark, aynı değere sahip satırlara nasıl sıra verdikleridir.
Kısa fark
| Fonksiyon | Eşit değerlere aynı sıra | Sonraki sırada boşluk |
|---|---|---|
| ROW_NUMBER | Hayır | Hayır |
| RANK | Evet | Evet |
| DENSE_RANK | Evet | Hayır |
Satış tutarları 1000, 900, 900, 700 ise:
| Tutar | ROW_NUMBER | RANK | DENSE_RANK |
|---|---|---|---|
| 1000 | 1 | 1 | 1 |
| 900 | 2 | 2 | 2 |
| 900 | 3 | 2 | 2 |
| 700 | 4 | 4 | 3 |
ROW_NUMBER kullanımı
SELECT
ProductName,
SalesAmount,
ROW_NUMBER() OVER (
ORDER BY SalesAmount DESC
) AS RowNo
FROM ProductSales;
Her satır benzersiz sıra numarası alır. Eşit tutarlar olsa bile numaralar tekrarlanmaz.
Sonucun her çalışmada tutarlı olması için ORDER BY bölümüne benzersiz bir ikinci alan eklemek iyi olur:
ROW_NUMBER() OVER (
ORDER BY SalesAmount DESC, ProductID
)
RANK kullanımı
SELECT
ProductName,
SalesAmount,
RANK() OVER (
ORDER BY SalesAmount DESC
) AS SalesRank
FROM ProductSales;
Eşit tutarlar aynı sırayı alır. Sonraki sıra atlanır. Yarışma sıralaması mantığına uygundur.
DENSE_RANK kullanımı
SELECT
ProductName,
SalesAmount,
DENSE_RANK() OVER (
ORDER BY SalesAmount DESC
) AS SalesRank
FROM ProductSales;
Eşit tutarlar aynı sırayı alır ancak sonraki sıra atlanmaz.
PARTITION BY ne işe yarar?
PARTITION BY, sıralamayı gruplar içinde yeniden başlatır:
SELECT
Category,
ProductName,
SalesAmount,
ROW_NUMBER() OVER (
PARTITION BY Category
ORDER BY SalesAmount DESC
) AS CategoryRowNo
FROM ProductSales;
Her kategori kendi içinde 1’den başlayarak sıralanır.
Her gruptan ilk 3 kayıt
Window function sonucu aynı SELECT’in WHERE bölümünde doğrudan filtrelenemeyeceği için CTE kullanılabilir:
WITH RankedProducts AS (
SELECT
Category,
ProductName,
SalesAmount,
ROW_NUMBER() OVER (
PARTITION BY Category
ORDER BY SalesAmount DESC
) AS RowNo
FROM ProductSales
)
SELECT *
FROM RankedProducts
WHERE RowNo <= 3;
Bu desen “her müşterinin son siparişi”, “her kategorinin en çok satan üç ürünü” ve “her çalışanın son kaydı” gibi sorularda sık kullanılır.
CTE yapısını ayrıntılı öğrenmek için SQL CTE ve WITH rehberine bakın.
Tekrarlı kayıtlardan birini seçmek
WITH DuplicateRows AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY Email
ORDER BY UpdatedAt DESC
) AS RowNo
FROM Customers
)
SELECT *
FROM DuplicateRows
WHERE RowNo = 1;
Her e-posta için en güncel kayıt seçilir. Silme işleminden önce tekillik kuralı ve veri kalitesi mutlaka doğrulanmalıdır.
Hangi fonksiyon seçilmeli?
- Her satıra benzersiz sıra gerekiyorsa:
ROW_NUMBER - Eşit sonuçlar aynı dereceyi alsın ve sıra atlansın isteniyorsa:
RANK - Eşit sonuçlar aynı dereceyi alsın ancak sıra atlanmasın isteniyorsa:
DENSE_RANK
Sık yapılan hatalar
ORDER BY kullanmamak
Bu fonksiyonlar OVER içindeki sıralama tanımına ihtiyaç duyar.
Eşit değerlerde sonucu deterministik sanmak
ROW_NUMBER eşit değerlerde benzersiz ikinci sıralama alanı yoksa satırlara farklı çalışmalarda farklı numara verebilir.
GROUP BY ile karıştırmak
GROUP BY satırları tek sonuçta toplar. Window function satırları koruyarak hesaplama yapar.
Büyük partition’ları dikkate almamak
Geniş sıralamalar bellek ve işlem maliyeti oluşturabilir. Filtre, indeks ve yürütme planı kontrol edilmelidir.
Uygulama
Temel SELECT, filtreleme, JOIN ve toplulaştırma alıştırmalarını ücretsiz SQL eğitiminde çalıştırabilirsiniz.
Sık sorulan sorular
ROW_NUMBER aynı numarayı iki kez verir mi?
Aynı sonuç kümesi içinde hayır; her satır farklı numara alır.
RANK neden 2’den sonra 4 verir?
İkinci sırayı iki kayıt paylaştığı için sonraki derece dördüncü sıradan devam eder.
PARTITION BY zorunlu mu?
Hayır. Kullanılmazsa tüm sonuç tek grup olarak sıralanır.