Sz
Sıfır Gecikme
veri bilimi · türkçe
Hakkımda🗺️ Haritam
Tümü
İnteraktif📖Rehber🛠Araç📊Vaka💼Kariyer🐍PY Playground🗄️SQL Playground🔍Regex📚Öğren🚀Proje
Ana sayfakariyer

Veri analisti mülakatında sorulan 10 SQL sorusu

senaryo · çözüm · sık yapılan hatalar · 20 dakika okuma

Veri analisti mülakatlarının büyük çoğunluğunda SQL testi var. Bazen beyaz tahta, bazen online editor, bazen sadece "şunu nasıl yazarsın?" sorusu olarak geliyor. Ama sorulan konular tahmin edilebilir.

Bu yazıdaki 10 soru, gerçek mülakatlarda en sık karşılaşılan yapıları kapsıyor. Her soru için senaryo, çözüm ve "burada takılıyorlar" notunu ekledim.

Sorularla pratik yapmak için SQL Playground'ı kullanabilirsin — tarayıcıda gerçek SQL motoru.


Soru 1

Her departmandaki çalışan sayısını bul

Senaryo: İnsan kaynakları veritabanında employees tablosu var. Her departmanda kaç çalışan olduğunu öğrenmek istiyorlar.

SELECT
  department,
  COUNT(*) AS calisан_sayisi
FROM employees
GROUP BY department
ORDER BY calisаn_sayisi DESC;

Sık yapılan hata: SELECT'te hem department hem desalary yazıp GROUP BY'a sadece department koymak.GROUP BY'da olmayan her sütun ya aggregate fonksiyona girmeli ya da dışarıda kalmalı.

Soru 2

Ortalamanın üzerinde maaş alan çalışanları listele

Senaryo: Maaşı şirket ortalamasının üzerinde olan çalışanların adını ve maaşını getir. Bu soru subquery kullanımını test ediyor.

SELECT
  name,
  salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
ORDER BY salary DESC;

Sık yapılan hata: WHERE salary > AVG(salary) yazmak — bu çalışmaz.WHEREiçinde aggregate fonksiyon kullanılamaz, subquery gerekir. Alternatif olarak CTE'yi de kabul ediyorlar:

WITH ortalama AS (
  SELECT AVG(salary) AS avg_salary FROM employees
)
SELECT name, salary
FROM employees, ortalama
WHERE salary > avg_salary;
Soru 3

Her müşterinin son siparişini getir

Senaryo: E-ticaret veritabanında orders tablosu var. Her müşterinin en son verdiği siparişin tarihini ve tutarını bul. Bu soru ROW_NUMBER() window fonksiyonu ya da subquery ile çözülüyor.

-- Window function ile (tercih edilen yol):
SELECT customer_id, order_date, amount
FROM (
  SELECT
    customer_id,
    order_date,
    amount,
    ROW_NUMBER() OVER (
      PARTITION BY customer_id
      ORDER BY order_date DESC
    ) AS rn
  FROM orders
) ranked
WHERE rn = 1;

Sık yapılan hata: MAX(order_date) ile tarihi doğru getirip tutarı yanlış eşleştirmek. GROUP BY customer_id yapınca amountbelirsizleşir — hangi siparişin tutarı? Window function bu sorunu çözer.

Soru 4

Birden fazla tablodaki veriyi birleştir — JOIN

Senaryo: Çalışanların adı employees tablosunda, departman adı ayrı bir departments tablosunda. Her çalışanın adını ve departman adını yan yana getir.

SELECT
  e.name,
  d.department_name,
  e.salary
FROM employees e
JOIN departments d ON e.department_id = d.id
ORDER BY d.department_name, e.name;

Mülakatta sorabilirler:"INNER JOIN ile LEFT JOIN farkı nedir?" Net cevap: INNER JOIN her iki tabloda eşleşen kayıtları getirir.LEFT JOIN sol tablonun tüm kayıtlarını getirir, sağda eşleşme yoksa NULL. Departmanı olmayan çalışanları da görmek istiyorsan LEFT JOIN.

Soru 5

Müşteri başına toplam harcamayı hesapla, 1000 TL altını filtrele

Senaryo:Sipariş tablosundan müşteri bazında toplam harcamayı bul, ama sadece toplamı 1000 TL'nin üzerindeki müşterileri göster. Bu soru HAVING kullanımını test ediyor.

SELECT
  customer_id,
  SUM(amount) AS toplam_harcama
FROM orders
GROUP BY customer_id
HAVING SUM(amount) > 1000
ORDER BY toplam_harcama DESC;

Sık yapılan hata: WHERE SUM(amount) > 1000 yazmak.WHERE satırları filtreler, HAVING grupları filtreler. Aggregate işlemi sonrası filtreleme her zaman HAVING.

Soru 6

Ay bazında satış trendini çıkar

Senaryo: Hangi ayda ne kadar satış yapıldı? Tarih sütunundan ay bilgisini çıkar, aylık toplamları hesapla. Zaman serisi ve tarih fonksiyonlarını test ediyor.

-- PostgreSQL / Standart SQL:
SELECT
  DATE_TRUNC('month', order_date) AS ay,
  COUNT(*) AS siparis_sayisi,
  SUM(amount) AS toplam_satis
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY ay;

-- SQLite (SQL Playground'da çalışır):
SELECT
  STRFTIME('%Y-%m', order_date) AS ay,
  COUNT(*) AS siparis_sayisi,
  SUM(amount) AS toplam_satis
FROM orders
GROUP BY STRFTIME('%Y-%m', order_date)
ORDER BY ay;

İpucu: Tarih fonksiyonları veritabanına göre değişiyor. Mülakatta hangi veritabanını kullandıklarını sor — DATE_TRUNC,STRFTIME, FORMAT hepsi farklı syntax.

Soru 7

Çalışanları maaşa göre sıralayıp sıra numarası ver

Senaryo: Her çalışana maaş sıralamasına göre bir numara ver. Window fonksiyonlarının temel sorusu — neredeyse her mülakatta çıkıyor.

SELECT
  name,
  department,
  salary,
  RANK() OVER (ORDER BY salary DESC) AS sirа,
  DENSE_RANK() OVER (ORDER BY salary DESC) AS yogun_sira,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS satir_no
FROM employees;

Mülakatta sorabilirler: "RANK, DENSE_RANK,ROW_NUMBERfarkı nedir?"

  • ROW_NUMBER: Eşit değerlere bile farklı numara verir (1, 2, 3, 4)
  • RANK: Eşit değerler aynı sıra, sonraki atlıyor (1, 1, 3, 4)
  • DENSE_RANK: Eşit değerler aynı sıra, sonraki atlamıyor (1, 1, 2, 3)
Soru 8

Hiç sipariş vermemiş müşterileri bul

Senaryo: customers ve orders tablosu var. Hiç sipariş vermemiş müşterilerin listesini getir. Üç farklı yol var — hangisini seçtiğin önemli.

-- Yol 1: LEFT JOIN + NULL kontrolü (yaygın ve okunabilir):
SELECT c.customer_id, c.name
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.customer_id IS NULL;

-- Yol 2: NOT EXISTS (büyük tablolarda genellikle daha hızlı):
SELECT customer_id, name
FROM customers c
WHERE NOT EXISTS (
  SELECT 1 FROM orders o
  WHERE o.customer_id = c.customer_id
);

-- Yol 3: NOT IN (dikkatli kullan — NULL varsa sorun çıkar):
SELECT customer_id, name
FROM customers
WHERE customer_id NOT IN (
  SELECT DISTINCT customer_id FROM orders
  WHERE customer_id IS NOT NULL  -- NULL varsa sonuç boş döner!
);

İpucu: Mülakatta üç yolu da bildiğini göster, tercihini ve nedenini açıkla.NOT IN'deki NULL tuzağını bilmek seni ayırt eder.

Soru 9

Running total — kümülatif toplam hesapla

Senaryo: Günlük satışların üzerine kümülatif toplamı ekle. Her gün o güne kadar yapılan toplam satışı göster.

SELECT
  order_date,
  daily_sales,
  SUM(daily_sales) OVER (
    ORDER BY order_date
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  ) AS kumulatif_satis
FROM (
  SELECT
    order_date,
    SUM(amount) AS daily_sales
  FROM orders
  GROUP BY order_date
) gunluk
ORDER BY order_date;

Neden önemli: Running total, retention analizi, LTV hesabı gibi gerçek iş sorularında çok kullanılıyor. Window frame (ROWS BETWEEN...) syntax'ını bilmek ileri seviye SQL bilen olduğunu gösterir.

Soru 10

Self join: yöneticiyi çalışanla eşleştir

Senaryo: Tek bir employees tablosunda hem çalışanlar hem yöneticiler var. Her çalışanın yanına yöneticisinin adını getir. Tablo kendisiyle join ediliyor.

SELECT
  e.name AS calisan,
  m.name AS yonetici,
  e.department,
  e.salary
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.employee_id
ORDER BY e.department, e.name;

Sık yapılan hata: INNER JOIN kullanmak — o zaman yöneticisi olmayan (tepedeki yönetici) kayıt siliniyor. LEFT JOIN ile yöneticisi olmayan çalışan da listede kalır, yönetici sütunu NULL döner.


Mülakat öncesi pratik planı

Mülakat 1 hafta sonraysa:

Mülakatı geçen SQL kodunu değil, düşünce sürecini satar. Yüksek sesle konuş: "Önce şunu anladım, şunu deneyeceğim, burada şu sorunu görüyorum." Sessiz kalmak seni saydamlaştırır.

Soru takıldığın, anlamadığın veya farklı çözüm yolu bulduysan X'ten yazabilirsin.

Sorularla pratik yapmak için: SQL Playground — e-ticaret, İK ve spor verisiyle gerçek SQL motoru.

Bunları da beğenebilirsin

kariyer

Veri analisti olarak ilk 90 günüm

12 dakika

kariyer

Veri analisti mi, data scientist mi, ML engineer mı?

12 dakika

kariyer

Veri analisti olma yol haritası

10 adım · interaktif

Faydalı bulduysan paylaş

X'te paylaşLinkedIn'de paylaş

💬 Yorumlar