SQL ile Veri Analizi: Temel Sorgulardan Window Functions'a
SELECT'ten window functions'a uzanan SQL yapılarını, gerçek hayattan veri analizi örnekleriyle adım adım inceliyorum.
- Araçlar

Veri analistliği söz konusu olduğunda SQL, en temel ve en sık kullanılan araçlardan biri. Çünkü analiz başlamadan önce çoğu zaman yapılması gereken ilk iş, veriyi bulunduğu kaynaktan doğru biçimde çekmek ve anlamlı bir yapıya dönüştürmek.
SQL öğrenirken yalnızca sorgu yazmayı değil, hangi soruyu hangi SQL yapısıyla çözebileceğimizi anlamak daha önemli. Bu yazıda en sık kullanılan SQL yapılarını gerçek hayattan örneklerle ele alıyorum.
“SQL'in gücü yalnızca veriyi getirmesinde değil, doğru soruyu verinin içinden çıkarabilmesindedir.”
SQL Veri Analizinde Neden Önemli?
Bir şirketin satış, müşteri, ürün, sipariş veya sosyal medya verilerinin büyük bölümünün veritabanlarında tutulduğunu düşünelim. Veri analistinin görevi çoğu zaman bu ham kayıtların içinden, sorulan iş sorusuna cevap verecek veriyi çıkarmaktır.
Doğru veriyi seçmek
Binlerce veya milyonlarca kaydın içinden yalnızca ihtiyaç duyulan kısmı almak.
Koşulları uygulamak
Tarih, kategori, müşteri veya kanal gibi kriterlerle veriyi daraltmak.
Veriyi toplulaştırmak
Satış, adet, müşteri sayısı gibi metrikleri gruplar bazında hesaplamak.
Sonucu yorumlamak
SQL çıktısını, iş problemine cevap veren analitik bir sonuca dönüştürmek.
- SELECT
- WHERE
- GROUP BY
- JOIN
- Analiz
1. SELECT — Hangi Veriye İhtiyacımız Var?
SQL öğrenirken ilk yapı SELECT. Bu komut, sorgudan hangi sütunları görmek istediğimizi belirler.
SELECT
musteri_id,
urun,
satis
FROM siparisler;Tek bir sütun seçebilir ya da veri setindeki tüm alanları alabiliriz:
SELECT urun
FROM siparisler;
-- Tüm sütunlar
SELECT *
FROM siparisler;2. WHERE — Veriyi Filtrelemek
Belirli bir koşulu sağlayan kayıtları almak için WHERE kullanılır.
SELECT *
FROM siparisler
WHERE satis > 5000;
-- Birden fazla koşul
SELECT *
FROM siparisler
WHERE satis > 5000
AND kategori = 'Elektronik';Bu yapı özellikle “Belirli bir dönemde belirli kategoride ne oldu?” gibi soruların ilk adımını oluşturur.
3. GROUP BY — Veriyi Gruplara Ayırmak
Analizde çoğu zaman tek tek kayıtları değil, grupları karşılaştırmak isteriz. Örneğin kategori bazında toplam satış:
SELECT
kategori,
SUM(satis) AS toplam_satis
FROM siparisler
GROUP BY kategori;
-- Şehir bazında benzersiz müşteri sayısı
SELECT
sehir,
COUNT(DISTINCT musteri_id) AS musteri_sayisi
FROM siparisler
GROUP BY sehir;| Fonksiyon | Ne için kullanılır? |
|---|---|
SUM() | Toplam değer |
COUNT() | Kayıt sayısı |
AVG() | Ortalama |
MIN() | Minimum değer |
MAX() | Maksimum değer |
4. HAVING — Gruplanmış Veriyi Filtrelemek
WHERE kayıtları filtrelerken, HAVING grup sonuçlarını filtrelemek için kullanılır.
SELECT
kategori,
SUM(satis) AS toplam_satis
FROM siparisler
GROUP BY kategori
HAVING SUM(satis) > 100000;WHERE = satırları filtrele, HAVING = grupları filtrele.5. JOIN — Farklı Tablolardan Veri Birleştirmek
Gerçek hayattaki veriler çoğu zaman tek tabloda bulunmaz. Müşteri bilgileri ayrı, siparişler ayrı, ürün bilgileri başka bir tabloda tutulabilir.
SELECT
s.siparis_id,
m.musteri_adi,
s.satis
FROM siparisler s
INNER JOIN musteriler m
ON s.musteri_id = m.musteri_id;Kesişim
Her iki tabloda eşleşen kayıtları getirir.
Sol tablo öncelikli
Sol tablodaki tüm kayıtları ve eşleşen sağ kayıtları getirir.
Sağ tablo öncelikli
Sağ tablodaki tüm kayıtları ve eşleşen sol kayıtları getirir.
Tüm kayıtlar
Her iki tablodaki eşleşen ve eşleşmeyen kayıtları bir araya getirir.
6. CASE WHEN — Veriyi Sınıflandırmak
Analizde ham sayıları anlamlı kategorilere dönüştürmek sık karşılaşılan bir ihtiyaç. CASE WHEN bunun için çok kullanışlı.
SELECT
musteri_id,
satis,
CASE
WHEN satis >= 10000 THEN 'Yüksek'
WHEN satis >= 5000 THEN 'Orta'
ELSE 'Düşük'
END AS satis_seviyesi
FROM siparisler;Bu yaklaşım müşteri segmentasyonu, performans sınıflandırması, risk grupları veya kampanya segmentleri gibi birçok analizde kullanılabilir.
7. Birkaç Yapıyı Birlikte Kullanmak
Asıl analitik güç, tek tek komutlardan ziyade bu yapıların birlikte kullanılmasında ortaya çıkıyor.
SELECT
kategori,
COUNT(*) AS siparis_sayisi,
SUM(satis) AS toplam_satis,
AVG(satis) AS ortalama_satis
FROM siparisler
WHERE tarih >= '2025-01-01'
GROUP BY kategori
HAVING SUM(satis) > 50000
ORDER BY toplam_satis DESC;Bu sorgu aslında tek bir komut değil, küçük bir analitik hikâye anlatıyor: belirli dönemi seç, kategorileri grupla, metrikleri hesapla, düşük hacimli grupları ele ve sonucu sırala.
8. Window Functions — Satırları Kaybetmeden Analiz
Window Functions, SQL'in veri analizi açısından en güçlü yapılarından biri. Toplulaştırma yaparken satırları kaybetmeden her satıra ek bilgi hesaplamamızı sağlar.
SELECT
kategori,
urun,
satis,
RANK() OVER (
PARTITION BY kategori
ORDER BY satis DESC
) AS kategori_sirasi
FROM urun_satislari;Burada her kategori kendi içinde sıralanıyor. Böylece “Her kategorinin en çok satan ürünleri hangileri?” sorusuna cevap verebiliriz.
ROW_NUMBER()
ROW_NUMBER() OVER (
PARTITION BY musteri_id
ORDER BY tarih DESC
) AS son_siparis_sirasiBu yapı bir müşterinin siparişlerini tarihe göre sıralamak ve örneğin son siparişi bulmak için kullanılabilir.
LAG() ve LEAD()
LAG(satis) OVER (
ORDER BY tarih
) AS onceki_satisLAG() önceki satırdaki değeri, LEAD() ise sonraki satırdaki değeri görmemizi sağlar. Zaman serilerinde dönemsel değişimleri analiz etmek için çok kullanışlıdır.
9. Gerçek Bir Analiz: Aylık Satış Değişimi
Örneğin aylık satışları hesaplayıp önceki ayla karşılaştırmak istediğimizi düşünelim.
WITH aylik_satis AS (
SELECT
DATE_TRUNC('month', tarih) AS ay,
SUM(satis) AS toplam_satis
FROM siparisler
GROUP BY DATE_TRUNC('month', tarih)
)
SELECT
ay,
toplam_satis,
LAG(toplam_satis) OVER (
ORDER BY ay
) AS onceki_ay_satis
FROM aylik_satis
ORDER BY ay;Bu sonuç daha sonra değişim oranı, büyüme trendi veya dashboard KPI'ları için kullanılabilir.
10. SQL'de Analitik Düşünmek
Bir veri analistinin SQL kullanırken yalnızca “Bu sorguyu nasıl yazarım?” diye düşünmesi yeterli değil. Daha önemli olan, soruyu parçalara ayırmak.
Ne görmek istiyorum?
Hangi metriği veya değişkeni analiz edeceğini belirle.
Veri nerede?
Gerekli tabloları ve aralarındaki ilişkileri bul.
Kapsam ne?
Tarih, segment, kanal veya diğer filtreleri tanımla.
Nasıl gruplayacağım?
İş sorusuna göre kategori, müşteri, dönem veya kanal seç.
Hangi hesap?
SUM, COUNT, AVG veya window function gibi doğru yapıyı seç.
Sonuç mantıklı mı?
Çıktıyı kontrol et ve iş bağlamında yorumla.
SQL Öğrenirken Sık Yapılan Hatalar
| Hata | Neden problem? | Daha iyi yaklaşım |
|---|---|---|
SELECT * her yerde kullanmak | Gereksiz sütunlar gelir. | İhtiyaç duyulan alanları seçmek. |
| JOIN mantığını kontrol etmemek | Kayıt sayısı beklenmedik şekilde çoğalabilir. | İlişkinin cardinality'sini kontrol etmek. |
| WHERE ve HAVING'i karıştırmak | Sorgu mantığı yanlış kurulur. | Satır filtresi / grup filtresi ayrımını düşünmek. |
| NULL değerleri göz ardı etmek | Hesaplamalar beklenenden farklı çıkabilir. | NULL davranışını ve COALESCE gibi yapıları kontrol etmek. |
| Sonucu doğrulamamak | Teknik olarak çalışan ama yanlış bir analiz oluşabilir. | Örnek kayıtlar ve bağımsız kontroller yapmak. |
SQL'de En Çok Kullanılan Yapılar
SELECT + WHERE
Veriyi seç ve ihtiyacın olmayan kayıtları filtrele.
GROUP BY + HAVING
Veriyi gruplandır, metrikleri hesapla ve grupları filtrele.
JOIN
Farklı tablolardan gelen bilgileri anlamlı biçimde birleştir.
CASE WHEN
Kurallara göre yeni kategoriler ve segmentler oluştur.
Window Functions
Sıralama, önceki/sonraki değer ve kümülatif analizler yap.
ORDER BY
Sonuçları analizin ihtiyacına göre düzenle.
Sonuç
SQL, veri analistliği için yalnızca teknik bir beceri değil; veriye soru sormanın temel yollarından biri. SELECT, WHERE, GROUP BY, HAVING, JOIN ve CASE WHEN gibi yapılar sağlam bir temel oluştururken, window functions daha ileri analizlerde önemli bir esneklik sağlıyor.
SQL öğrenirken hedef yüzlerce sorguyu ezberlemek olmamalı. Bunun yerine bir iş sorusunu alıp onu küçük parçalara ayırmayı ve her parçayı doğru SQL yapısıyla çözmeyi öğrenmek çok daha değerli.
“İyi SQL sadece çalışan sorgu değildir; doğru soruya, doğru veriden, güvenilir bir cevap üreten sorgudur.”
When it comes to working as a data analyst, SQL is one of the most fundamental and most frequently used tools. Because before any analysis starts, the first job is usually to pull the data correctly from where it lives and turn it into a meaningful shape.
While learning SQL, understanding which question can be solved with which SQL structure matters more than simply writing queries. In this post I go through the most commonly used SQL structures with real-life examples.
“The power of SQL is not only in fetching data, but in being able to pull the right question out of it.”
Why Does SQL Matter in Data Analysis?
Think of a company where most of the sales, customer, product, order or social media data is kept in databases. The data analyst's job is usually to extract, from those raw records, the data that answers the business question being asked.
Selecting the right data
Taking only the part you need out of thousands or millions of records.
Applying conditions
Narrowing the data with criteria such as date, category, customer or channel.
Aggregating the data
Calculating metrics such as sales, quantity or customer count by group.
Interpreting the result
Turning the SQL output into an analytical answer to the business problem.
- SELECT
- WHERE
- GROUP BY
- JOIN
- Analysis
1. SELECT — Which Data Do We Need?
The first structure you meet in SQL is SELECT. It defines which columns you want to see in the result.
SELECT
customer_id,
product,
sales
FROM orders;You can select a single column, or take every field in the data set:
SELECT product
FROM orders;
-- All columns
SELECT *
FROM orders;2. WHERE — Filtering the Data
WHERE is used to take only the records that satisfy a given condition.
SELECT *
FROM orders
WHERE sales > 5000;
-- More than one condition
SELECT *
FROM orders
WHERE sales > 5000
AND category = 'Electronics';This structure is the first step of questions such as “What happened in a given category during a given period?”.
3. GROUP BY — Splitting the Data into Groups
In analysis we usually want to compare groups rather than individual records. Total sales by category, for example:
SELECT
category,
SUM(sales) AS total_sales
FROM orders
GROUP BY category;
-- Unique customers by city
SELECT
city,
COUNT(DISTINCT customer_id) AS customer_count
FROM orders
GROUP BY city;| Function | What is it used for? |
|---|---|
SUM() | Total value |
COUNT() | Number of records |
AVG() | Average |
MIN() | Minimum value |
MAX() | Maximum value |
4. HAVING — Filtering Grouped Data
While WHERE filters records, HAVING is used to filter group results.
SELECT
category,
SUM(sales) AS total_sales
FROM orders
GROUP BY category
HAVING SUM(sales) > 100000;WHERE = filter the rows, HAVING = filter the groups.5. JOIN — Combining Data from Different Tables
Real-life data rarely sits in a single table. Customer information, orders and product details are often kept in separate tables.
SELECT
o.order_id,
c.customer_name,
o.sales
FROM orders o
INNER JOIN customers c
ON o.customer_id = c.customer_id;Intersection
Returns the records that match in both tables.
Left table first
Returns all records from the left table plus the matching right ones.
Right table first
Returns all records from the right table plus the matching left ones.
All records
Brings together both matching and non-matching records from both tables.
6. CASE WHEN — Classifying the Data
Turning raw numbers into meaningful categories is a common need in analysis, and CASE WHEN is very handy for it.
SELECT
customer_id,
sales,
CASE
WHEN sales >= 10000 THEN 'High'
WHEN sales >= 5000 THEN 'Medium'
ELSE 'Low'
END AS sales_level
FROM orders;The same approach can be used in customer segmentation, performance classification, risk groups or campaign segments.
7. Using Several Structures Together
The real analytical power appears when these structures are used together rather than one by one.
SELECT
category,
COUNT(*) AS order_count,
SUM(sales) AS total_sales,
AVG(sales) AS average_sales
FROM orders
WHERE order_date >= '2025-01-01'
GROUP BY category
HAVING SUM(sales) > 50000
ORDER BY total_sales DESC;This query is not really a single command; it tells a small analytical story: pick the period, group the categories, calculate the metrics, drop the low-volume groups and sort the result.
8. Window Functions — Analysis Without Losing Rows
Window functions are one of SQL's most powerful structures for data analysis. They let you calculate extra information for every row while aggregating, without losing the rows themselves.
SELECT
category,
product,
sales,
RANK() OVER (
PARTITION BY category
ORDER BY sales DESC
) AS category_rank
FROM product_sales;Here every category is ranked within itself, so we can answer “Which are the best-selling products of each category?”.
ROW_NUMBER()
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC
) AS last_order_rankThis structure can be used to sort a customer's orders by date and find the most recent one, for example.
LAG() and LEAD()
LAG(sales) OVER (
ORDER BY order_date
) AS previous_salesLAG() shows the value in the previous row and LEAD() the value in the next one. They are very useful for analysing period-over-period change in time series.
9. A Real Analysis: Monthly Sales Change
Imagine we want to calculate monthly sales and compare each month with the previous one.
WITH monthly_sales AS (
SELECT
DATE_TRUNC('month', order_date) AS month,
SUM(sales) AS total_sales
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
)
SELECT
month,
total_sales,
LAG(total_sales) OVER (
ORDER BY month
) AS previous_month_sales
FROM monthly_sales
ORDER BY month;This result can then be used for change rates, growth trends or dashboard KPIs.
10. Thinking Analytically in SQL
It is not enough for a data analyst to ask only “How do I write this query?”. Breaking the question into pieces matters more.
What do I want to see?
Decide which metric or variable you are going to analyse.
Where is the data?
Find the tables you need and the relationships between them.
What is the scope?
Define the date, segment, channel and any other filters.
How will I group it?
Choose category, customer, period or channel according to the business question.
Which calculation?
Pick the right structure: SUM, COUNT, AVG or a window function.
Does the result make sense?
Check the output and interpret it in its business context.
Common Mistakes When Learning SQL
| Mistake | Why is it a problem? | Better approach |
|---|---|---|
Using SELECT * everywhere | Unnecessary columns come along. | Select only the fields you need. |
| Not checking the JOIN logic | The number of records can multiply unexpectedly. | Check the cardinality of the relationship. |
| Mixing up WHERE and HAVING | The query logic ends up wrong. | Think about the row filter / group filter distinction. |
| Ignoring NULL values | Calculations can differ from what you expect. | Check NULL behaviour and structures such as COALESCE. |
| Not validating the result | An analysis can run technically and still be wrong. | Look at sample records and run independent checks. |
The Most Used Structures in SQL
SELECT + WHERE
Select the data and filter out the records you do not need.
GROUP BY + HAVING
Group the data, calculate the metrics and filter the groups.
JOIN
Bring together information from different tables in a meaningful way.
CASE WHEN
Create new categories and segments based on rules.
Window functions
Do ranking, previous/next value and cumulative analyses.
ORDER BY
Arrange the results according to what the analysis needs.
Conclusion
SQL is not only a technical skill for a data analyst; it is one of the basic ways of asking questions of data. Structures such as SELECT, WHERE, GROUP BY, HAVING, JOIN and CASE WHEN build a solid foundation, while window functions add important flexibility for more advanced analyses.
The goal while learning SQL should not be memorising hundreds of queries. It is far more valuable to take a business question, break it into small pieces and learn to solve each piece with the right SQL structure.
“Good SQL is not just a query that runs; it is a query that produces a reliable answer to the right question from the right data.”