← Kursa Dön
📄 Text · 25 min

DISTINCT ve Alias (AS)

Giriş — Tekrar Edenler ve Okunabilirlik

İki temel konuyu bu derste ele alacağız: DISTINCT ile tekrar eden sonuçları elemek ve AS ile sütunlara/tablolara anlamlı isimler vermek. Her ikisi de günlük SQL yazımında sürekli karşına çıkacak.

🎯 Analoji: Bir sınıfta "Hangi şehirlerden öğrencilerimiz var?" diye soruyorsun. Yoklama listesinde İstanbul 15 kez, Ankara 8 kez, İzmir 5 kez geçiyor. Ama sen her şehri bir kez duymak istiyorsun: "İstanbul, Ankara, İzmir." İşte DISTINCT tam bunu yapar — tekrarları eler, her değeri bir kez gösterir.


DISTINCT — Tekrar Eden Satırları Eleme

Temel Kullanım

-- Müşterilerimiz hangi şehirlerden?
SELECT city FROM customers;
-- İstanbul, Ankara, İzmir, İstanbul, Bursa, Antalya, İstanbul, Ankara, İzmir, İstanbul
-- 10 satır, birçok tekrar

-- Tekrarları ele: Her şehir bir kez
SELECT DISTINCT city FROM customers;
-- İstanbul, Ankara, İzmir, Bursa, Antalya
-- 5 satır, benzersiz değerler

Birden Fazla Sütunla DISTINCT

DISTINCT, satır bazında benzersizlik sağlar. Birden fazla sütun belirtildiğinde, sütunların kombinasyonu benzersiz olur:

-- Her müşteri-şehir kombinasyonu
SELECT DISTINCT city, is_active FROM customers;
-- İstanbul, 1
-- Ankara, 1
-- İzmir, 1
-- Bursa, 0
-- Antalya, 0
-- İstanbul, 0  (varsa)
-- Sipariş verilen benzersiz müşteri-ürün çiftleri
SELECT DISTINCT oi.product_id, o.customer_id
FROM order_items oi
JOIN orders o ON oi.order_id = o.order_id;
-- Her müşterinin hangi ürünleri aldığı (tekrarsız)

DISTINCT ve NULL

-- NULL değerler DISTINCT'te TEK BİR NULL olarak ele alınır
SELECT DISTINCT phone FROM customers;
-- 05551001001
-- 05551001002
-- ...
-- NULL  (tüm NULL'lar tek satırda gösterilir)

DISTINCT ve ORDER BY

-- Benzersiz şehirler, alfabetik sıralı
SELECT DISTINCT city 
FROM customers 
ORDER BY city ASC;

-- Benzersiz kategorilerin fiyat aralıkları
SELECT DISTINCT category_id 
FROM products 
WHERE price > 1000
ORDER BY category_id;

COUNT(DISTINCT ...) — Benzersiz Değerleri Say

-- Kaç farklı şehirden müşterimiz var?
SELECT COUNT(DISTINCT city) AS unique_cities FROM customers;
-- Sonuç: 5

-- Kaç farklı müşteri sipariş vermiş?
SELECT COUNT(DISTINCT customer_id) AS unique_customers FROM orders;
-- Sonuç: 7

-- Kaç farklı ürün satılmış?
SELECT COUNT(DISTINCT product_id) AS unique_products FROM order_items;
-- Sonuç: 10

DISTINCT vs GROUP BY

Her ikisi de benzersiz değerler üretebilir ama amaçları farklıdır:

-- DISTINCT — sadece benzersiz değerler
SELECT DISTINCT city FROM customers;

-- GROUP BY — benzersiz değerler + aggregate
SELECT city, COUNT(*) AS customer_count 
FROM customers 
GROUP BY city;
DISTINCTGROUP BY
Tekrar elemeGruplama + aggregate
Aggregate fonksiyon gerekmiyorAggregate fonksiyon kullanılabilir
Sadece benzersiz değerleri gösterGrupla ve hesapla

💡 İpucu: Sadece benzersiz değer listesi istiyorsan DISTINCT yeterli. Benzersiz değerlerle birlikte sayma, toplama gibi işlem yapacaksan GROUP BY kullan.


DISTINCT Performans

-- DISTINCT, sonuçları sıralamak veya hash'lemek zorundadır — maliyet vardır
SELECT DISTINCT city FROM customers;
-- Küçük tablolarda fark etmez

-- Büyük tablolarda DISTINCT yavaşlayabilir
SELECT DISTINCT customer_email FROM million_row_table;
-- MySQL: temporary table + sort veya hash

-- Eğer sütunda index varsa DISTINCT daha hızlı çalışır
CREATE INDEX idx_city ON customers(city);
SELECT DISTINCT city FROM customers;
-- Index scan — çok daha hızlı

⚠️ Dikkat: SELECT DISTINCT * her sütunu dahil ettiği için neredeyse her satır "benzersiz" olur (primary key farklı olduğu için). Genellikle anlamsızdır ve performans israfıdır.


Alias (AS) — Sütun ve Tablo İsimlendirme

Sütun Alias'ı

-- Hesaplamalı sütuna isim ver
SELECT 
    product_name,
    price AS normal_fiyat,
    price * 0.90 AS indirimli_fiyat,
    price * 1.20 AS kdv_dahil_fiyat,
    stock_quantity AS stok
FROM products;

AS keyword'ü opsiyoneldir — boşluk da yeterli ama AS daha okunabilir:

-- AS ile (önerilen)
SELECT first_name AS ad, last_name AS soyad FROM customers;

-- AS olmadan (çalışır ama daha az okunabilir)
SELECT first_name ad, last_name soyad FROM customers;

Boşluklu Alias

-- Boşluk veya özel karakter içeren alias — tırnak kullan
SELECT 
    product_name AS "Ürün Adı",
    price AS "Fiyat (TL)",
    stock_quantity AS "Stok Durumu"
FROM products;

-- MySQL'de backtick de çalışır
SELECT 
    product_name AS `Ürün Adı`,
    price AS `Fiyat (TL)`
FROM products;

Tablo Alias'ı

-- Uzun tablo isimlerini kısalt
SELECT c.first_name, c.last_name, o.total_amount
FROM customers AS c
JOIN orders AS o ON c.customer_id = o.customer_id;

-- AS olmadan (yaygın kullanım)
SELECT c.first_name, c.last_name, o.total_amount
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id;

Tablo alias'ları özellikle JOIN'lerde zorunlu hale gelir — aynı sütun adı birden fazla tabloda olduğunda hangi tablodan geldiğini belirtmelisin.

Alias Kullanım Kuralları

-- ✅ ORDER BY'da alias kullanılabilir
SELECT price * 1.20 AS kdv_dahil FROM products ORDER BY kdv_dahil DESC;

-- ❌ WHERE'da alias KULLANILAMAZ (henüz tanımlı değil)
SELECT price * 1.20 AS kdv_dahil FROM products WHERE kdv_dahil > 1000;
-- ERROR! WHERE, SELECT'ten önce çalışır

-- ✅ WHERE'da hesaplamayı tekrar yaz
SELECT price * 1.20 AS kdv_dahil FROM products WHERE price * 1.20 > 1000;

-- ✅ HAVING'de alias kullanılabilir (GROUP BY sonrası)
SELECT city, COUNT(*) AS musteri_sayisi 
FROM customers 
GROUP BY city 
HAVING musteri_sayisi > 2;

CONCAT ile Ad Birleştirme — Alias'ın Gerçek Kullanımı

-- Ad ve soyadı birleştir
SELECT CONCAT(first_name, ' ', last_name) AS full_name,
       email,
       COALESCE(city, 'Belirtilmemiş') AS sehir
FROM customers
WHERE is_active = TRUE
ORDER BY full_name ASC;
+----------------+-------------------+-------------+
| full_name      | email             | sehir       |
+----------------+-------------------+-------------+
| Ahmet Yılmaz   | ahmet@email.com   | İstanbul    |
| Ayşe Çelik     | ayse@email.com    | İstanbul    |
| Can Koç        | can@email.com     | Ankara      |
| ...            | ...               | ...         |
+----------------+-------------------+-------------+

Gerçek Dünya Örneği — Ürün Kataloğu

-- E-ticaret ürün kataloğu sorgusu
SELECT 
    p.product_id AS "ID",
    p.product_name AS "Ürün",
    COALESCE(c.category_name, 'Kategorisiz') AS "Kategori",
    CONCAT('₺', FORMAT(p.price, 2)) AS "Fiyat",
    CONCAT('₺', FORMAT(p.price * 0.90, 2)) AS "İndirimli Fiyat",
    CASE 
        WHEN p.stock_quantity = 0 THEN 'Tükendi'
        WHEN p.stock_quantity < 10 THEN 'Son Birkaç Adet'
        ELSE 'Stokta'
    END AS "Stok Durumu"
FROM products p
LEFT JOIN categories c ON p.category_id = c.category_id
WHERE p.is_active = TRUE
ORDER BY p.price DESC
LIMIT 20;

ALL Keyword'ü (DISTINCT'in Tersi)

-- ALL varsayılandır — tüm satırları döndürür (tekrarlar dahil)
SELECT ALL city FROM customers;
-- = SELECT city FROM customers;  (aynı şey)

-- DISTINCT — tekrarları eler
SELECT DISTINCT city FROM customers;

ALL pratikte hiç kullanılmaz çünkü zaten varsayılan davranış budur. Ama varlığını bilmek iyi olur.


Sıkça Yapılan Hatalar

  1. SELECT DISTINCT * kullanmak: Primary key her satırı benzersiz kılar, yani DISTINCT * neredeyse hiçbir şeyi elemez. Gereksiz performans maliyeti.

  2. DISTINCT'i WHERE yerine kullanmak: Veri tekrarının sebebi kötü tablo tasarımı veya yanlış JOIN olabilir. DISTINCT'i "düzeltme bandajı" olarak kullanmak yerine sorgunun doğruluğunu kontrol et.

  3. Alias'ı WHERE'de kullanmak: SQL değerlendirme sırasını unutma — WHERE, SELECT'ten önce çalışır.

  4. Türkçe karakter alias'larda tırnak unutmak: AS Ürün Adı hata verir. AS "Ürün Adı" veya AS \Ürün Adı\`` kullan.

  5. DISTINCT ile COUNT karışıklığı: COUNT(DISTINCT city) farklı şehir sayısını, COUNT(city) NULL olmayan şehir sayısını, COUNT(*) tüm satır sayısını verir.


Özet

  • DISTINCT tekrar eden satırları eler, her değeri bir kez gösterir

  • DISTINCT satır bazında çalışır — birden fazla sütunda kombinasyon benzersizliği

  • COUNT(DISTINCT sütun) benzersiz değer sayısını verir

  • DISTINCT performans maliyeti var — gereksiz yere kullanma

  • AS ile sütun ve tablolara alias (takma ad) verilir

  • AS keyword'ü opsiyonel ama okunabilirlik için önerilir

  • Alias WHERE'de kullanılamaz, ORDER BY ve HAVING'de kullanılabilir

  • Boşluklu alias'lar tırnak veya backtick içine yazılır