Dünkü temellere şimdi analiz becerileri ekliyoruz. Sıralama, gruplama, toplam-ortalama hesaplama ve veriyi şekillendirme — bunlar T-SQL’in günlük ekmek peyniri.

1. ORDER BY — Sıralama

SELECT Name, Salary FROM Employees
ORDER BY Salary DESC;

Birden Fazla Kritere Göre

SELECT * FROM Employees
ORDER BY Department ASC, Salary DESC;
-- Önce departmana göre artan, aynı departmandakileri maaşa göre azalan

Sütun Numarasıyla (kısa ama dikkat)

SELECT Name, Department, Salary FROM Employees
ORDER BY 3 DESC;  -- 3. sütun = Salary

Production’da sütun adı yaz — sütun pozisyonu değişirse sorgun bozulur.

2. Sayfalama: OFFSET / FETCH

SELECT * FROM Employees
ORDER BY Id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;

Sayfalama yaparken mutlaka ORDER BY kullan. Yoksa sıra garanti değil, aynı sorguyu iki kez çalıştırınca farklı sonuçlar gelebilir.

3. Aggregate Fonksiyonlar

Birden fazla satırı tek değere indirgerler:

FonksiyonAçıklama
COUNT(*)Satır sayısı (NULL dahil)
COUNT(column)NULL hariç satır sayısı
SUM(column)Toplam
AVG(column)Ortalama
MIN(column)En küçük
MAX(column)En büyük
SELECT
    COUNT(*) AS TotalEmployees,
    AVG(Salary) AS AvgSalary,
    MIN(Salary) AS MinSalary,
    MAX(Salary) AS MaxSalary,
    SUM(Salary) AS TotalSalary
FROM Employees;

4. GROUP BY — Gruplama

Veriyi sütun değerine göre grupla, sonra aggregate fonksiyon uygula:

SELECT Department, COUNT(*) AS Total, AVG(Salary) AS AvgSal
FROM Employees
GROUP BY Department;

Sonuç:

Department  | Total | AvgSal
IT          | 12    | 8500.00
Marketing   | 8     | 6200.00
HR          | 5     | 5800.00

Önemli Kural

GROUP BY kullandığında, SELECT’deki her sütun ya aggregate fonksiyon içinde olmalı, ya da GROUP BY’da yer almalı:

-- ✗ HATA
SELECT Department, Name, COUNT(*) FROM Employees GROUP BY Department;
-- Name ne aggregate ne GROUP BY'da

-- ✓ Doğru
SELECT Department, COUNT(*) FROM Employees GROUP BY Department;

5. HAVING — Grup Filtresi

WHERE satırları filtreler, HAVING grupları:

SELECT Department, COUNT(*) AS Total
FROM Employees
GROUP BY Department
HAVING COUNT(*) > 5;
-- Sadece 5'ten fazla çalışanı olan departmanlar

WHERE vs HAVING

SELECT Department, COUNT(*) AS Total
FROM Employees
WHERE Active = 1                  -- önce satırları filtrele
GROUP BY Department
HAVING COUNT(*) > 5;              -- sonra grupları filtrele

Sıra: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

6. DISTINCT — Benzersiz Değerler

SELECT DISTINCT Country FROM Employees;
-- Tekrar etmeyen ülkeler

SELECT DISTINCT Country, City FROM Employees;
-- Ülke-şehir benzersiz kombinasyonları

7. CASE WHEN — Koşullu Sütunlar

Sorgu içinde if/else mantığı:

SELECT
    Name,
    Salary,
    CASE
        WHEN Salary < 5000 THEN 'Düşük'
        WHEN Salary BETWEEN 5000 AND 10000 THEN 'Orta'
        WHEN Salary > 10000 THEN 'Yüksek'
        ELSE 'Belirsiz'
    END AS SalaryBracket
FROM Employees;

Aggregate ile Birlikte (Conditional Count)

SELECT
    COUNT(*) AS Total,
    SUM(CASE WHEN Salary > 10000 THEN 1 ELSE 0 END) AS HighEarners,
    SUM(CASE WHEN Department = 'IT' THEN 1 ELSE 0 END) AS ITStaff
FROM Employees;

Tek sorguda birden fazla “alt-count” alabilirsin — pivot benzeri.

8. String Fonksiyonları

FonksiyonÖrnekSonuç
LEN(s)LEN('Hello')5
UPPER(s)UPPER('abc')'ABC'
LOWER(s)LOWER('XYZ')'xyz'
LTRIM, RTRIMLTRIM(' hi')'hi'
TRIMTRIM(' hi ')'hi'
SUBSTRING(s, start, len)SUBSTRING('abcdef', 2, 3)'bcd'
LEFT(s, n)LEFT('abcdef', 3)'abc'
RIGHT(s, n)RIGHT('abcdef', 2)'ef'
REPLACE(s, a, b)REPLACE('abc', 'b', 'X')'aXc'
CONCAT(a, b, c)CONCAT('Hi', ' ', 'World')'Hi World'
CHARINDEX(sub, s)CHARINDEX('cd', 'abcdef')3

Örnek: E-posta Domain Çıkarma

SELECT
    Email,
    SUBSTRING(Email, CHARINDEX('@', Email) + 1, LEN(Email)) AS Domain
FROM Users;

9. Tarih Fonksiyonları

SELECT GETDATE();                  -- şu an (DATETIME)
SELECT SYSDATETIME();              -- daha yüksek hassasiyet

-- Bileşenler
SELECT YEAR(HireDate), MONTH(HireDate), DAY(HireDate) FROM Employees;

-- Tarih aritmetiği
SELECT DATEADD(YEAR, 1, GETDATE());     -- 1 yıl ekle
SELECT DATEADD(MONTH, -6, GETDATE());   -- 6 ay çıkar
SELECT DATEADD(DAY, 30, HireDate);

-- İki tarih arası fark
SELECT DATEDIFF(YEAR, HireDate, GETDATE()) AS YearsWorked FROM Employees;
SELECT DATEDIFF(DAY, OrderDate, ShipDate) FROM Orders;

-- Formatlama (SQL Server 2012+)
SELECT FORMAT(GETDATE(), 'dd MMMM yyyy', 'tr-TR');  -- 27 Mayıs 2026
SELECT FORMAT(Salary, 'C', 'tr-TR');                -- ₺ formatı

Yaygın DATEDIFF Birimleri

YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, WEEK, QUARTER

Pratik Sorular

Soru 1: Her departmanın en yüksek maaşını listele.

SELECT Department, MAX(Salary) AS MaxSalary
FROM Employees
GROUP BY Department
ORDER BY MaxSalary DESC;

Soru 2: Ortalama maaşı 7000’den fazla olan departmanları getir.

SELECT Department, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY Department
HAVING AVG(Salary) > 7000;

Soru 3: Çalışanları maaşa göre 3 kategoriye ayır ve her kategorideki kişi sayısını ver.

SELECT
    CASE
        WHEN Salary < 5000 THEN 'Düşük'
        WHEN Salary < 10000 THEN 'Orta'
        ELSE 'Yüksek'
    END AS Bracket,
    COUNT(*) AS Total
FROM Employees
GROUP BY
    CASE
        WHEN Salary < 5000 THEN 'Düşük'
        WHEN Salary < 10000 THEN 'Orta'
        ELSE 'Yüksek'
    END;

Soru 4: Son 1 yıl içinde işe alınan çalışanların ortalama maaşı.

SELECT AVG(Salary) AS RecentAvgSalary
FROM Employees
WHERE HireDate >= DATEADD(YEAR, -1, GETDATE());

Soru 5: En çok çalışanı olan ilk 5 departman.

SELECT TOP 5
    Department,
    COUNT(*) AS Total
FROM Employees
GROUP BY Department
ORDER BY Total DESC;

Günün Özeti

Bugün analitik sorgu becerilerini öğrendik:

Yarın Gün 3’te JOIN’lere geçiyoruz — birden fazla tabloyu birleştirip gerçek ilişkisel sorgular yazacağız.