Web & Yazılım Geliştirme Serisi · Modül 8
Veritabanı ve SQL'i öğren
İlişkisel tablolar, veri tipleri ve birincil anahtar; SELECT, WHERE, ORDER BY ile sorgular; INSERT/UPDATE/DELETE, yabancı anahtar ve JOIN'ler; gruplama, normalizasyon, indeksler ve güvenlik. Her bölümde özgün diyagramlar ve "sorgu ne döndürür?" kartıyla.
Veritabanı ve Tablolar
Temeller: veritabanı nedir, ilişkisel tablolar, sütunlar ve veri tipleri, birincil anahtar; ilk sorgular SELECT, WHERE, ORDER BY, LIMIT ve DISTINCT.
Bölüm 01
Veritabanı Nedir?
Veritabanı, verinin düzenli, güvenli ve hızlı erişilebilir biçimde saklandığı bir sistemdir. Birkaç satırlık veriyi bir dosyada tutabilirsin; ama binlerce kullanıcı, sipariş ve ürünü güvenle yönetmek için veritabanı gerekir.
Neden dosya değil, veritabanı?
- Hız: milyonlarca kayıt arasından saniyede arama.
- Bütünlük: kurallar ve ilişkilerle veri tutarlı kalır.
- Eşzamanlılık: birçok kullanıcı aynı anda güvenle erişir.
- Güvenlik: kimin neye erişebileceği denetlenir.
Bu modülde ilişkisel veritabanlarına ve onların dili olan SQL'e odaklanacağız — bunlar sektörün en yaygın temelidir. SQL (Structured Query Language), neredeyse tüm ilişkisel veritabanlarında (MySQL, PostgreSQL, SQLite, SQL Server) benzer biçimde çalışır; bir kez öğrenince hepsine yakın olursun. Backend modülünde gördüğün "sunucu veritabanına bakar" cümlesinin somut hâli budur.
Sorgu ne döndürür?
SonuçBir veritabanına "kayıtlı kullanıcıların listesini ver" gibi bir sorgu gönderirsin; veritabanı bu sorguya bir sonuç (genelde bir satır kümesi / tablo) döner. SQL, bu sorguları yazdığın dildir.
Alıştırma
8 dkVeritabanını kavra:
- Bir alışveriş sitesinin hangi verileri saklaması gerektiğini listele.
- Bu veriyi bir dosyada tutmanın üç zorluğunu yaz.
- SQL'in ne işe yaradığını kendi cümlenle açıkla.
Bölüm 02
İlişkisel Veritabanı ve Tablolar
İlişkisel veritabanında veri, tablolarda tutulur. Bir tablo, satırlardan (kayıtlar) ve sütunlardan (alanlar) oluşur — tıpkı bir elektronik tablo gibi, ama kurallar ve ilişkilerle. Her tablo tek bir "şeyi" temsil eder: kullanıcılar, ürünler, siparişler.
Tablonun yapısı
- Sütun (column): bir alan (örn. ad, eposta) — dikey.
- Satır (row): bir kayıt (bir kullanıcı) — yatay.
- Hücre: bir satır ve sütunun kesişimi (bir değer).
Her tabloya tek bir "varlık" düşür: kullanıcılar bir tabloda, siparişler ayrı bir tabloda. Bir tabloya birbiriyle ilgisiz şeyleri (kullanıcılar + ürünler) karıştırmak, ileride büyük baş ağrısı yaratır. Tablo isimleri genelde çoğul ve küçük harftir (kullanicilar, urunler). İyi tablo tasarımı, iyi veritabanının temelidir.
Sorgu ne döndürür?
Sonuçkullanicilar tablosundan veri istediğinde, veritabanı sana satırlardan oluşan bir sonuç döner. Her satır bir kullanıcıyı, her sütun o kullanıcının bir özelliğini (ad, şehir) temsil eder.
Alıştırma
10 dkTablo tasarla:
- Bir kütüphane için "kitaplar" tablosunun sütunlarını belirle.
- Üç örnek satır (kayıt) yaz.
- Hangi verilerin ayrı bir tabloda (örn. "yazarlar") olması gerektiğini düşün.
Bölüm 03
Sütunlar ve Veri Tipleri
Her sütunun bir veri tipi vardır: o sütunda ne tür değerlerin tutulacağını belirler. Doğru tip seçmek, veriyi hem doğru saklar hem de hatalara karşı korur.
Yaygın veri tipleri
- INTEGER: tam sayı (yaş, adet, id).
- VARCHAR / TEXT: metin (ad, açıklama).
- DECIMAL: ondalıklı sayı (fiyat, tutar).
- DATE / TIMESTAMP: tarih ve zaman.
- BOOLEAN: doğru/yanlış (aktif mi?).
Tablo oluşturma (CREATE TABLE)
CREATE TABLE urunler (
id INTEGER PRIMARY KEY,
ad VARCHAR(100),
fiyat DECIMAL(10,2),
stokta BOOLEAN,
eklenme DATE
);Veri tipini doğru seç: parayı asla ondalık hatalarına açık türlerle değil, DECIMAL ile sakla; tarihleri metin yerine DATE olarak tut (böylece sıralama ve karşılaştırma doğru çalışır). Doğru tip, veritabanının senin için bir "bekçi" gibi çalışmasını sağlar: yanlış türde veri girmeye çalışırsan reddeder, böylece veri temiz kalır.
Sorgu ne döndürür?
SonuçBir sütunu INTEGER tanımlarsan, oraya metin koymaya çalışınca veritabanı hata verir ve reddeder. Bu sayede "yaş" sütununda asla "yirmi" gibi bir metin bulunmaz — veri tipleri, veriyi baştan doğru tutmanı sağlar.
Alıştırma
10 dkTip seç:
- Bir "öğrenciler" tablosunun her sütunu için uygun veri tipini yaz.
- Fiyat için neden DECIMAL kullanılır, açıkla.
- Bir CREATE TABLE ifadesi yaz (en az 4 sütun).
Bölüm 04
Birincil Anahtar (Primary Key)
Her tabloda, her satırı benzersiz biçimde tanımlayan bir sütun olmalıdır: birincil anahtar (primary key). Genelde bu, otomatik artan bir "id" sütunudur. Birincil anahtar, bir satıra kesin olarak işaret etmenin yoludur.
Birincil anahtarın kuralları
- Benzersiz: iki satırda aynı değer olamaz.
- Boş olamaz: her satırın bir anahtarı olmalı.
- Değişmez: bir kez atanınca değiştirilmez.
Neden ad veya e-posta yerine bir id? Çünkü adlar tekrar edebilir (iki "Ayşe Yılmaz"), e-postalar değişebilir. Sayısal, otomatik artan bir id ise her zaman benzersiz ve değişmezdir — bir satıra güvenle işaret etmenin tek sağlam yolu odur. Birincil anahtar, bir sonraki bölümlerde tabloları birbirine bağlamanın da (yabancı anahtar) temeli olacak.
Sorgu ne döndürür?
Sonuçid = 2 dediğinde, veritabanı tam olarak tek bir satırı (Veli) döner — başka hiçbir satırın id'si 2 olamaz. Birincil anahtar, "hangi satır?" sorusuna her zaman tek ve kesin bir cevap verir.
Alıştırma
8 dkAnahtar seç:
- Bir "arabalar" tablosu için iyi bir birincil anahtar öner.
- Neden "marka" sütununun birincil anahtar olamayacağını açıkla.
- Birincil anahtarın üç kuralını kendi örneğinde göster.
Bölüm 05
İlk Sorgu: SELECT
SELECT, SQL'in en temel ve en sık kullanılan komutudur: bir tablodan veri okur. "Şu sütunları, şu tablodan getir" dersin; veritabanı sana sonuç olarak satırları döner.
SELECT'in yapısı
SELECT sütunlar— hangi alanları istiyorsun.FROM tablo— hangi tablodan.SELECT *— tüm sütunları getir.
Temel SELECT sorguları
-- Tüm sütunları, tüm satırları getir:
SELECT * FROM kullanicilar;
-- Yalnızca ad ve şehir sütununu getir:
SELECT ad, sehir FROM kullanicilar;Üretimde SELECT * yerine ihtiyacın olan sütunları açıkça yaz: bu hem daha hızlıdır (gereksiz veri taşınmaz) hem de tabloya sütun eklendiğinde sorgun beklenmedik biçimde değişmez. SQL komutlarının sonuna noktalı virgül (;) koymak gelenektir. SQL büyük/küçük harfe duyarsızdır ama anahtar kelimeleri (SELECT, FROM) BÜYÜK yazmak okunabilirliği artırır.
Sorgu ne döndürür?
SonuçSELECT ad, sehir FROM kullanicilar sorgusu, tablodaki her satır için yalnızca ad ve sehir sütunlarını içeren bir sonuç döner — id ve e-posta gibi istemediğin alanlar gelmez. İstediğin sütunları sen belirlersin.
Alıştırma
10 dkSELECT yaz:
- Bir "urunler" tablosundan tüm sütunları getiren sorguyu yaz.
- Yalnızca ad ve fiyat sütununu getiren sorguyu yaz.
- SELECT * ile sütunları tek tek yazmanın farkını açıkla.
Bölüm 06
Süzme: WHERE
Çoğu zaman tüm satırları değil, bir koşulu sağlayanları istersin: "şehri Ankara olanlar", "fiyatı 100'den büyük ürünler". WHERE komutu, sonucu bir koşula göre süzer.
WHERE ile koşul
- Karşılaştırma:
=,>,<,>=,<=,<>(eşit değil). - Birleştirme:
AND,OR,NOT. - Metin arama:
LIKE '%ankara%'; aralık:BETWEEN; liste:IN.
WHERE ile süzme
-- Şehri Ankara olan kullanıcılar:
SELECT ad FROM kullanicilar WHERE sehir = 'Ankara';
-- Fiyatı 100'den büyük ürünler:
SELECT ad, fiyat FROM urunler WHERE fiyat > 100;SQL'de metin değerleri tek tırnak içinde yazılır ('Ankara'), sayılar tırnaksız. En sık hata, eşitlik için == kullanmaktır — SQL'de eşitlik tek = ile yazılır. Bir WHERE koşulunu yanlış kurmak (veya unutmak) yanlış satırların gelmesine yol açar; özellikle UPDATE ve DELETE'te bu çok tehlikelidir (sonraki seviyede göreceğiz).
Sorgu ne döndürür?
SonuçWHERE sehir = 'Ankara' koşulu, yalnızca şehri tam olarak "Ankara" olan satırları döner; diğerleri sonuçta yer almaz. Koşulu değiştirerek (örn. fiyat > 100) farklı süzme sonuçları elde edersin.
Alıştırma
12 dkWHERE yaz:
- "Yaşı 18'den büyük kullanıcılar" sorgusunu yaz.
- "Stokta olan ve fiyatı 50'den az ürünler" için AND kullan.
- Metin değerlerinin neden tırnak içinde yazıldığını açıkla.
Bölüm 07
Sıralama ve Sınırlama: ORDER BY, LIMIT
Sonuçları belirli bir düzende görmek (en pahalıdan ucuza, A'dan Z'ye) ve yalnızca ilk birkaçını almak çok yaygındır. ORDER BY sıralar, LIMIT ise sonuç sayısını kısıtlar.
Sıralama ve sınırlama
ORDER BY sütun— artan (ASC, varsayılan).ORDER BY sütun DESC— azalan.LIMIT n— yalnızca ilk n satır.
ORDER BY ve LIMIT
-- En pahalı 3 ürün:
SELECT ad, fiyat FROM urunler
ORDER BY fiyat DESC
LIMIT 3;ORDER BY ve LIMIT birlikte çok güçlüdür: "en yeni 10 yorum", "en çok satan 5 ürün" gibi sorgular bu ikilisiyle yazılır. Sıralama olmadan LIMIT kullanmak rastgele satırlar getirebilir — "ilk 3" demek için önce neye göre sıralandığını belirtmelisin. Sıra: önce ORDER BY, sonra LIMIT.
Sorgu ne döndürür?
SonuçORDER BY fiyat DESC LIMIT 3, önce ürünleri fiyata göre en pahalıdan ucuza sıralar, sonra yalnızca ilk 3'ünü döner. ORDER BY olmadan LIMIT, hangi 3 satırın geleceğini garanti etmez.
Alıştırma
10 dkSırala ve sınırla:
- Kullanıcıları ada göre A'dan Z'ye sıralayan sorguyu yaz.
- "En yeni 5 kayıt" için ORDER BY ve LIMIT kullan.
- ORDER BY olmadan LIMIT kullanmanın riskini açıkla.
Bölüm 08
Tekil Değerler: DISTINCT
Bazen bir sütundaki tekrar eden değerleri değil, yalnızca benzersiz olanları görmek istersin: "kaç farklı şehir var?" gibi. DISTINCT, sonuçtaki yinelenen satırları teke indirir.
DISTINCT ile tekilleştirme
SELECT DISTINCT sütun— benzersiz değerleri getirir.- Tekrar eden değerler tek satıra iner.
- "Kaç farklı X var?" sorularının ilk adımı.
DISTINCT ile benzersiz değerler
-- Kullanıcıların bulunduğu farklı şehirler:
SELECT DISTINCT sehir FROM kullanicilar;Tabloda "Ankara" beş kez geçse bile, SELECT DISTINCT sehir onu sonuçta yalnızca bir kez gösterir. DISTINCT, "elimde kaç farklı kategori/şehir/durum var?" gibi sorulara hızlı cevap verir. Bir sonraki seviyede bunu sayma (COUNT) ve gruplama (GROUP BY) ile birleştirerek çok daha güçlü özetler çıkaracaksın.
Sorgu ne döndürür?
SonuçTabloda üç kullanıcı Ankara'da olsa bile, SELECT DISTINCT sehir "Ankara"yı yalnızca bir kez döner. Sonuç, sütundaki benzersiz değerlerin listesidir — kaç farklı şehir olduğunu bir bakışta görürsün.
Alıştırma
8 dkDISTINCT kullan:
- Bir "siparisler" tablosundan farklı ödeme yöntemlerini getiren sorguyu yaz.
- DISTINCT'in tekrarları nasıl ele aldığını açıkla.
- "Kaç farklı ülke var?" sorusuna giden ilk adımı yaz.
Veriyi Değiştirmek ve İlişkiler
Veriyi yönetmek ve bağlamak: INSERT, UPDATE, DELETE; yabancı anahtar ile ilişkiler; tabloları JOIN ile birleştirmek ve JOIN türleri.
Bölüm 09
Veri Eklemek: INSERT
Bir tabloya yeni satır eklemek için INSERT komutu kullanılır. Hangi sütunlara hangi değerleri koyacağını belirtirsin; veritabanı yeni kaydı tabloya ekler.
INSERT'in yapısı
INSERT INTO tablo (sütunlar)— hangi alanlar.VALUES (değerler)— sırasıyla değerler.- Birincil anahtar genelde otomatik atanır.
INSERT ile satır ekleme
INSERT INTO kullanicilar (ad, sehir, eposta)
VALUES ('Deniz', 'Ankara', '[email protected]');
-- Birden çok satır:
INSERT INTO kullanicilar (ad, sehir) VALUES
('Ece', 'İzmir'),
('Mert', 'Bursa');Sütun adlarını açıkça yazmak iyi bir alışkanlıktır (INSERT INTO ... (ad, sehir)): böylece tabloya yeni sütun eklendiğinde sorgun bozulmaz ve hangi değerin nereye gittiği nettir. Değerler, belirttiğin sütun sırasına birebir uymalıdır. Metinler tek tırnakta, sayılar tırnaksız yazılır — Bölüm 6'daki kuralla aynı.
Sorgu ne döndürür?
SonuçINSERT komutu bir sonuç kümesi döndürmez; bunun yerine tabloyu değiştirir (yeni satır ekler). İşlem sonrası SELECT * FROM kullanicilar çalıştırırsan, yeni eklediğin satırı diğerleriyle birlikte görürsün.
Alıştırma
10 dkINSERT yaz:
- Bir "urunler" tablosuna yeni bir ürün ekleyen INSERT yaz.
- Tek bir komutla iki ürün birden ekle.
- Sütun adlarını açıkça yazmanın faydasını açıkla.
Bölüm 10
Veri Güncellemek: UPDATE
Var olan satırları değiştirmek için UPDATE kullanılır: bir fiyatı güncellemek, bir adresi düzeltmek gibi. En kritik nokta, hangi satırların güncelleneceğini WHERE ile doğru belirlemektir.
UPDATE'in yapısı
UPDATE tablo SET sütun = değer— neyi değiştir.WHERE koşul— hangi satırlarda (çok önemli!).- WHERE unutulursa: tüm satırlar değişir.
UPDATE ile güncelleme
-- Doğru: yalnızca id = 3 olan satırı güncelle
UPDATE kullanicilar
SET sehir = 'İstanbul'
WHERE id = 3;
-- TEHLİKELİ: WHERE yok -> herkesin şehri değişir!
UPDATE kullanicilar SET sehir = 'İstanbul';UPDATE'i her zaman WHERE ile sınırla. WHERE olmadan çalıştırılan bir UPDATE, tablodaki tüm satırları değiştirir — bu, gerçek projelerde yaşanan en yıkıcı hatalardan biridir. Güvenli alışkanlık: önce aynı WHERE ile bir SELECT çalıştırıp hangi satırların etkileneceğini gör, sonra UPDATE'i yaz. Bir sonraki seviyede göreceğin "işlemler" (transactions) bu tür hataları geri almanı sağlar.
Sorgu ne döndürür?
SonuçUPDATE ... WHERE id = 3, yalnızca 3 numaralı satırı günceller ve kaç satırın etkilendiğini bildirir (örn. "1 satır güncellendi"). WHERE'i kaldırırsan bu sayı tüm tablo olur — bu yüzden çalıştırmadan önce iki kez düşün.
Alıştırma
12 dkUPDATE yaz:
- Bir ürünün fiyatını güncelleyen, yalnızca o ürünü etkileyen UPDATE yaz.
- WHERE'siz bir UPDATE'in neden tehlikeli olduğunu açıkla.
- Güvenli güncelleme için önce hangi sorguyu çalıştırırsın?
Bölüm 11
Veri Silmek: DELETE
Satırları silmek için DELETE kullanılır. UPDATE gibi, DELETE de WHERE ile sınırlanmalıdır — yoksa tablodaki tüm satırlar silinir. Silme işlemi çoğu zaman geri alınamaz, bu yüzden en dikkatli yaklaşılması gereken komuttur.
DELETE'in yapısı
DELETE FROM tablo WHERE koşul— eşleşenleri sil.- WHERE unutulursa: tüm satırlar silinir.
- Silme genelde kalıcıdır; geri alınamaz.
DELETE ile silme
-- Doğru: yalnızca id = 5 olan satırı sil
DELETE FROM kullanicilar WHERE id = 5;
-- TEHLİKELİ: WHERE yok -> TÜM kullanıcılar silinir!
DELETE FROM kullanicilar;DELETE, SQL'in en tehlikeli komutudur: yanlış (veya eksik WHERE'li) bir DELETE, saniyeler içinde tüm veriyi yok edebilir. Korunma yolları: (1) önce aynı WHERE ile SELECT çalıştır, (2) kritik işlemleri bir "işlem" (transaction) içinde yap (gerekirse ROLLBACK), (3) düzenli yedek al (Bölüm 24). Birçok sistem, gerçekten silmek yerine "silindi" işareti koyar (soft delete) — böylece veri kurtarılabilir.
Sorgu ne döndürür?
SonuçDELETE FROM kullanicilar WHERE id = 5 yalnızca tek satırı siler. WHERE olmadan aynı komut tüm tabloyu boşaltır — ve çoğu durumda bunu geri almanın tek yolu bir yedektir. Bu yüzden DELETE'ten önce her zaman dur ve WHERE'ini kontrol et.
Alıştırma
10 dkDELETE yaz:
- Tek bir siparişi silen, güvenli bir DELETE yaz.
- WHERE'siz DELETE'in sonucunu açıkla.
- Gerçek silme yerine "soft delete" yaklaşımını anlat.
Bölüm 12
İlişkiler ve Yabancı Anahtar (Foreign Key)
İlişkisel veritabanının gücü, tabloları birbirine bağlamasıdır. Bir tablodaki yabancı anahtar (foreign key), başka bir tablodaki birincil anahtara işaret eder — böylece "bu sipariş hangi kullanıcıya ait?" sorusu yanıtlanabilir.
Tabloları bağlamak
- Birincil anahtar (PK): bir satırı tanımlar (örn. kullanicilar.id).
- Yabancı anahtar (FK): başka tablonun PK'sine işaret eder.
- Böylece veri tekrarı önlenir, ilişkiler kurulur.
Yabancı anahtar, veri tekrarını önler ve bütünlüğü korur: her siparişte kullanıcının tüm bilgilerini tekrar yazmak yerine, sadece kullanici_id'sini tutarsın. Çoğu veritabanı, var olmayan bir kullanıcıya işaret eden bir sipariş eklemeni de engeller (referans bütünlüğü). Bu ilişki türü ("bir kullanıcının çok siparişi") en yaygın olanıdır: bir-çok (1→N).
Sorgu ne döndürür?
Sonuçsiparisler tablosundaki bir satırın kullanici_id = 1 değeri, o siparişin kullanicilar tablosundaki 1 numaralı satıra (Ayşe) ait olduğunu söyler. Bu bağ sayesinde, bir sonraki bölümde iki tabloyu birleştirip "Ayşe'nin siparişlerini" tek sorguda getirebileceksin.
Alıştırma
12 dkİlişki tasarla:
- "yazarlar" ve "kitaplar" tabloları arasında bir ilişki kur.
- Hangi tabloya yabancı anahtar koyarsın? Neden?
- Yabancı anahtarın veri tekrarını nasıl önlediğini açıkla.
Bölüm 13
Tabloları Birleştirmek: JOIN
İlişkili veriyi tek bir sonuçta görmek için tabloları JOIN ile birleştirirsin: "her siparişi, ait olduğu kullanıcının adıyla birlikte göster". JOIN, ilişkisel veritabanını gerçekten güçlü kılan komuttur.
INNER JOIN
- İki tabloyu, eşleşen bir sütun (PK = FK) üzerinden birleştirir.
ONile eşleşme koşulu belirtilir.- INNER JOIN: yalnızca her iki tabloda da eşleşen satırlar.
INNER JOIN ile birleştirme
SELECT siparisler.id, kullanicilar.ad, siparisler.tutar
FROM siparisler
INNER JOIN kullanicilar
ON siparisler.kullanici_id = kullanicilar.id;JOIN'in kalbi ON koşuludur: hangi sütunların eşleşeceğini söyler (genelde bir tablonun FK'si = diğerinin PK'si). Sütun adları iki tabloda da aynıysa (örn. ikisinde de id), hangi tablonunkini kastettiğini tablo.sutun ile belirtmelisin. INNER JOIN, eşleşmeyen satırları (örn. hiç siparişi olmayan kullanıcı) sonuçtan dışlar — onları da istiyorsan LEFT JOIN gerekir (sonraki bölüm).
Sorgu ne döndürür?
SonuçBu INNER JOIN, her siparişi ait olduğu kullanıcının adıyla eşleştirip tek bir tabloda döner: sipariş id, kullanıcı adı, tutar. Yalnızca geçerli bir kullanıcıya bağlı siparişler görünür — kullanıcısı olmayan (ya da hiç siparişi olmayan kullanıcı) bu sonuçta yer almaz.
Alıştırma
14 dkJOIN yaz:
- "kitaplar" ve "yazarlar" tablolarını yazar adıyla birlikte getiren JOIN yaz.
- ON koşulunun hangi sütunları eşleştirdiğini belirt.
- INNER JOIN'in hangi satırları dışladığını açıkla.
Bölüm 14
JOIN Türleri
INNER JOIN yalnızca eşleşenleri getirir; ama bazen "siparişi olmasa bile tüm kullanıcıları" görmek istersin. Farklı JOIN türleri, hangi eşleşmeyen satırların da dahil edileceğini belirler.
Dört temel JOIN türü
- INNER JOIN: yalnızca her iki tabloda eşleşenler.
- LEFT JOIN: soldaki tablonun tümü + eşleşenler.
- RIGHT JOIN: sağdaki tablonun tümü + eşleşenler.
- FULL JOIN: her iki tablonun tüm satırları.
LEFT JOIN örneği
-- Tüm kullanıcılar; siparişi olmayanların tutarı NULL olur
SELECT kullanicilar.ad, siparisler.tutar
FROM kullanicilar
LEFT JOIN siparisler
ON kullanicilar.id = siparisler.kullanici_id;Türü ihtiyacına göre seç: "yalnızca sipariş vermiş kullanıcılar" → INNER; "tüm kullanıcılar, sipariş vermemiş olsalar bile" → LEFT JOIN. LEFT JOIN'de eşleşme bulunmayan yerlerde değerler NULL gelir (örn. siparişi olmayan kullanıcının tutarı NULL). Pratikte en sık INNER ve LEFT JOIN kullanılır; RIGHT ve FULL daha nadirdir (ve RIGHT, tabloların yerini değiştirerek LEFT ile yazılabilir).
Sorgu ne döndürür?
SonuçBu LEFT JOIN, hiç siparişi olmayan kullanıcıları da sonuca dahil eder — onların tutar alanı NULL görünür. Aynı sorguyu INNER JOIN ile yazsaydın, siparişi olmayan kullanıcılar tamamen kaybolurdu. JOIN türü, "eksik eşleşmelerle ne yapılacağını" belirler.
Alıştırma
12 dkTür seç:
- "Hiç kitap yazmamış yazarları da listele" için hangi JOIN türü?
- LEFT JOIN'de eşleşmeyen satırlarda hangi değer görünür?
- RIGHT JOIN'in neden LEFT ile yazılabileceğini açıkla.
Özetleme ve Tasarım
Veriden anlam çıkarmak: GROUP BY ile gruplama, toplama fonksiyonları, HAVING; normalizasyon, indeksler ve veritabanı tasarımı.
Bölüm 15
Gruplama: GROUP BY
Tek tek satırlar yerine özetler istediğinde GROUP BY kullanırsın: "her şehirde kaç kullanıcı var?", "her kategorinin toplam satışı ne?". GROUP BY, satırları ortak bir değere göre gruplar ve her grup için tek bir özet satır üretir.
GROUP BY mantığı
- Satırları bir sütunun değerine göre gruplar (örn. her şehir).
- Her grup için bir toplama fonksiyonu hesaplanır (COUNT, SUM...).
- Sonuç: her grup için tek bir özet satır.
GROUP BY ile gruplama
-- Her şehirde kaç kullanıcı var?
SELECT sehir, COUNT(*) AS adet
FROM kullanicilar
GROUP BY sehir;GROUP BY'ın temel kuralı: SELECT'te yer alan her sütun ya GROUP BY'da olmalı ya da bir toplama fonksiyonu içinde kullanılmalıdır. Örneğin sehir'e göre grupluyorsan, SELECT'te sehir (gruplanan) ve COUNT(*) (toplama) olabilir ama tek bir kullanıcının ad'ı olamaz — çünkü bir grupta birçok ad vardır. AS ile sonuç sütununa anlamlı bir isim verebilirsin.
Sorgu ne döndürür?
SonuçGROUP BY sehir, aynı şehirdeki tüm satırları tek bir grupta toplar; COUNT(*) her grubun kaç satır içerdiğini sayar. Sonuçta her şehir bir kez görünür, yanında o şehirdeki kullanıcı sayısıyla — ham satırlar yerine bir özet elde edersin.
Alıştırma
12 dkGROUP BY yaz:
- "Her kategoride kaç ürün var?" sorgusunu yaz.
- Sonucun kaç satır olacağını tahmin et (kategori sayısı kadar).
- GROUP BY kuralını (SELECT'teki sütunlar) açıkla.
Bölüm 16
Toplama Fonksiyonları
Toplama (aggregate) fonksiyonları, bir grup satırı tek bir değere indirir: kaç tane (COUNT), toplam (SUM), ortalama (AVG), en büyük (MAX), en küçük (MIN). GROUP BY ile birlikte, verinden güçlü özetler çıkarırsın.
Beş temel fonksiyon
- COUNT: satır/değer sayısı.
- SUM: sayısal toplam.
- AVG: ortalama.
- MAX / MIN: en büyük / en küçük.
Toplama fonksiyonları
-- Her kategorinin toplam ve ortalama fiyatı:
SELECT kategori,
COUNT(*) AS urun_sayisi,
SUM(fiyat) AS toplam,
AVG(fiyat) AS ortalama
FROM urunler
GROUP BY kategori;COUNT(*) tüm satırları sayar; COUNT(sutun) ise o sütunda NULL olmayan değerleri sayar — bu fark bazen önemlidir. Toplama fonksiyonları GROUP BY olmadan da kullanılabilir; o zaman tüm tabloyu tek bir gruba indirirler (örn. SELECT AVG(fiyat) FROM urunler tüm ürünlerin ortalama fiyatını verir). Bu fonksiyonlar, raporlama ve analizin temelidir.
Sorgu ne döndürür?
SonuçBu sorgu her kategori için üç özet üretir: ürün sayısı (COUNT), fiyatların toplamı (SUM) ve ortalaması (AVG). GROUP BY ile birleştiğinde, "hangi kategori en çok ürüne / en yüksek ortalamaya sahip?" gibi sorulara tek sorguda yanıt alırsın.
Alıştırma
12 dkÖzet çıkar:
- Tüm siparişlerin toplam tutarını bulan sorguyu yaz (SUM).
- Her kullanıcının ortalama sipariş tutarını GROUP BY ile bul.
- COUNT(*) ile COUNT(sutun) arasındaki farkı açıkla.
Bölüm 17
Grupları Süzmek: HAVING
WHERE, satırları süzer; ama gruplandıktan sonra grupları süzmek istersen (örn. "yalnızca 5'ten fazla siparişi olan kullanıcılar") HAVING kullanılır. HAVING, GROUP BY'ın sonucuna uygulanan bir filtredir.
WHERE ve HAVING farkı
- WHERE: gruplamadan önce, tek tek satırları süzer.
- HAVING: gruplamadan sonra, grupları süzer.
- HAVING genelde bir toplama fonksiyonu içerir (örn. COUNT(*) > 5).
HAVING ile grup süzme
-- 5'ten fazla siparişi olan kullanıcılar:
SELECT kullanici_id, COUNT(*) AS siparis_sayisi
FROM siparisler
GROUP BY kullanici_id
HAVING COUNT(*) > 5;Anahtar ayrım: WHERE satırlara, HAVING gruplara uygulanır. "Fiyatı 100'den büyük ürünleri kategorilere göre say" derken: önce WHERE fiyat > 100 (satırları süz), sonra GROUP BY kategori, sonra istersen HAVING COUNT(*) > 3 (grupları süz). İkisi aynı sorguda birlikte kullanılabilir. Toplama sonucuna göre süzmek istiyorsan WHERE değil HAVING gerekir.
Sorgu ne döndürür?
SonuçBu sorgu önce siparişleri kullanıcıya göre gruplar, her grubun sayısını bulur, sonra HAVING ile yalnızca 5'ten fazla siparişi olan grupları bırakır. Sonuç: "çok sipariş veren" kullanıcıların listesi — sadık müşterileri bulmanın bir yolu.
Alıştırma
12 dkHAVING yaz:
- "10'dan fazla ürünü olan kategoriler" sorgusunu yaz.
- WHERE ile HAVING arasındaki farkı bir örnekle açıkla.
- Aynı sorguda hem WHERE hem HAVING kullanılan bir durum düşün.
Bölüm 18
Normalizasyon
Normalizasyon, veriyi tekrar etmeyecek ve tutarsızlığa düşmeyecek biçimde tablolara bölmektir. Tek bir şişman tabloda her şeyi tutmak ilk başta kolay görünür ama veri tekrarına ve hatalara yol açar.
Neden bölmeli?
- Veri tekrarı yer israfı ve tutarsızlık riskidir.
- Bir bilgi tek bir yerde tutulmalı (örn. kullanıcı adı).
- Tekrar eden veriyi ayrı tabloya çıkar, ilişkiyle bağla.
Klasik örnek: siparişler tablosunda her satıra kullanıcının adını, adresini, telefonunu yazarsan, aynı kullanıcının her siparişinde bu bilgiler tekrarlanır. Kullanıcı adresini değiştirince tüm siparişlerini güncellemen gerekir — birini atlarsan veri tutarsız olur. Çözüm: kullanıcı bilgisini bir kez kullanicilar tablosunda tut, siparişlerde sadece kullanici_id (FK) bulundur. "Her gerçek tek bir yerde" — normalizasyonun özü budur.
Sorgu ne döndürür?
SonuçNormalize edilmiş tasarımda kullanıcı adı yalnızca kullanicilar tablosunda bir kez bulunur; siparişler ona kullanici_id ile bağlanır. Ad değişince tek bir satırı güncellersin ve tüm siparişler otomatik olarak doğru adı (JOIN ile) gösterir. Tekrar yok, tutarsızlık yok.
Alıştırma
12 dkNormalize et:
- Her satırda müşteri bilgisini tekrar eden bir "şişman" tablo düşün.
- Bu tabloyu iki ilişkili tabloya böl.
- Bölmenin hangi tutarsızlık riskini ortadan kaldırdığını açıkla.
Bölüm 19
İndeksler (Index)
Bir tablo büyüdükçe, bir değeri aramak yavaşlar — çünkü veritabanı tüm satırları taramak zorunda kalabilir. İndeks, tıpkı bir kitabın dizini gibi, aranan değere doğrudan gitmeyi sağlayarak sorguları çok hızlandırır.
İndeks ne yapar?
- İndekssiz arama: tüm satırları tek tek tara (yavaş).
- İndeksli arama: doğrudan ilgili satıra atla (hızlı).
- Sık aranan/filtrelenen sütunlara indeks eklenir.
İndeksin bir bedeli vardır: aramayı hızlandırır ama yazma işlemlerini (INSERT/UPDATE) biraz yavaşlatır ve yer kaplar (dizin de güncellenmeli). Bu yüzden her sütuna değil, sık aranan/filtrelenen/JOIN edilen sütunlara indeks koyarsın. Birincil anahtarlar genelde otomatik indekslenir. Kural: önce sorgu yaz, yavaşsa ve sık çalışıyorsa indeks ekle — erken ve aşırı indeksleme ters teper.
Sorgu ne döndürür?
Sonuçİndekssiz bir tabloda WHERE eposta = '[email protected]' milyonlarca satırı taramak zorunda kalabilir. eposta sütununa indeks eklersen, veritabanı dizini kullanıp doğru satıra neredeyse anında ulaşır — sorgu saniyelerden milisaniyelere iner.
Alıştırma
10 dkİndeksi düşün:
- Bir "kullanicilar" tablosunda hangi sütuna indeks eklerdin? Neden?
- İndeksin yazma işlemlerine etkisini açıkla.
- Neden her sütuna indeks eklemek iyi fikir değildir?
Bölüm 20
Veritabanı Tasarımı
İyi bir veritabanı, kod yazmadan önce iyi tasarlanır. Hangi tablolar, hangi sütunlar, hangi ilişkiler? Bu kararları baştan doğru vermek, ileride çok büyük yeniden yazımları önler.
Tasarım adımları
- Varlıkları belirle: sistemdeki "şeyler" (kullanıcı, ürün, sipariş).
- Her varlık bir tablo: sütunlarını ve birincil anahtarını tanımla.
- İlişkileri kur: yabancı anahtarlarla bağla.
- Normalize et: tekrarı önle.
Tasarıma kâğıt üstünde bir ER (Varlık-İlişki) şemasıyla başla: kutular tablolar, oklar ilişkiler. Kodlamadan önce şemayı netleştirmek, Modül 6'daki "önce planla, sonra kodla" ilkesinin veritabanı karşılığıdır. İyi sorular: "Bu varlık başka neye bağlı? Bir X'in kaç Y'si olur (bir-bir, bir-çok, çok-çok)? Hangi bilgi nerede, tek bir yerde tutuluyor mu?" Çok-çok ilişkiler genelde bir ara tablo gerektirir.
Sorgu ne döndürür?
SonuçBu tasarımda her ürün bir kategori_id ile bir kategoriye bağlıdır; bir kategorinin birçok ürünü olabilir (çok-bir). Kategori adı yalnızca kategoriler tablosunda bir kez tutulur. İyi tasarlanmış bir şema, sorguları kolay, veriyi tutarlı ve sistemi büyümeye hazır kılar.
Alıştırma
16 dkŞema tasarla:
- Bir blog için varlıkları belirle (yazılar, yazarlar, yorumlar, etiketler).
- Her varlık için bir tablo ve birincil anahtar tasarla.
- Tablolar arası ilişkileri (yabancı anahtarlarla) çiz.
Güvenlik ve Üretim
Gerçek dünya: SQL enjeksiyonu ve parametreli sorgu, işlemler (transactions), görünümler, yedekleme, NoSQL'e bakış ve küçük bir şema tasarlamak.
Bölüm 21
SQL Enjeksiyonu ve Parametreli Sorgu
SQL enjeksiyonu, en yaygın ve en tehlikeli güvenlik açıklarından biridir: kullanıcı girdisi doğrudan bir SQL sorgusuna gömülürse, saldırgan kendi SQL'ini çalıştırabilir. Çözüm basit ve kesindir: parametreli sorgular.
Tehlike ve çözüm
- Tehlike: kullanıcı girdisini metin olarak sorguya yapıştırmak.
- Sonuç: saldırgan sorguyu değiştirip veri çalabilir/silebilir.
- Çözüm: parametreli sorgu — girdi "veri" olarak işlenir, "kod" olarak değil.
Tehlikeli vs güvenli (kavramsal)
// TEHLİKELİ: girdi doğrudan sorguya gömülür
sorgu = "SELECT * FROM kullanicilar WHERE ad = '" + girdi + "'"
// GÜVENLİ: parametreli sorgu (yer tutucu kullan)
sorgu = "SELECT * FROM kullanicilar WHERE ad = ?"
calistir(sorgu, [girdi]) // girdi yalnızca veri olarak giderBu, Backend modülündeki "kullanıcı verisine asla güvenme" ilkesinin somut hâlidir. Kural mutlaktır: kullanıcı girdisini asla SQL metnine birleştirme; her zaman parametreli sorgu (hazırlanmış ifadeler / prepared statements) kullan. Parametreli sorguda girdi, sorgunun yapısını değiştiremez — sadece bir değer olarak yerine konur. Bu tek alışkanlık, SQL enjeksiyonunu neredeyse tamamen ortadan kaldırır. PHP, Python ve C# modüllerinde bunun dile özgü biçimlerini göreceksin.
Sorgu ne döndürür?
SonuçGüvenli sürümde ? bir yer tutucudur; veritabanı önce sorgunun yapısını derler, sonra girdiyi yalnızca bir değer olarak yerleştirir. Böylece saldırgan girdiye SQL kodu yazsa bile, o kod çalışmaz — sadece aranan bir metin olarak ele alınır. Sorgu yapısı saldırgana kapalıdır.
Alıştırma
12 dkGüvenliği uygula:
- Girdiyi birleştiren tehlikeli bir sorguyu parametreli hâle çevir.
- Parametreli sorgunun enjeksiyonu neden engellediğini açıkla.
- "Kullanıcı verisine güvenme" ilkesini SQL bağlamında yaz.
Bölüm 22
İşlemler (Transactions)
Bazı işlemler birden çok adımdan oluşur ve hepsi ya birlikte başarılı olmalı ya da hiçbiri olmamalı. Para transferi gibi: bir hesaptan düş, diğerine ekle. İşlemler (transactions), bu "ya hep ya hiç" güvencesini sağlar.
İşlem mantığı
BEGINile başla, adımları çalıştır.- Hepsi başarılıysa
COMMIT(kalıcı yap). - Bir adım başarısızsa
ROLLBACK(hepsini geri al).
İşlemler veri bütünlüğünün koruyucusudur. Para transferinde ilk UPDATE çalışıp ikincisi (örn. elektrik kesintisi) çalışmazsa, para "buharlaşır". İşlem içine alırsan, ikinci adım başarısız olunca ilk adım da geri alınır (ROLLBACK) — hesaplar tutarlı kalır. Bu güvenceye ACID denir (Atomiklik, Tutarlılık, İzolasyon, Dayanıklılık). Kritik, çok adımlı işlemleri her zaman bir işlem içinde yap.
Sorgu ne döndürür?
SonuçBir işlem içinde iki UPDATE çalıştırırsın; ikisi de başarılıysa COMMIT değişiklikleri kalıcı yapar. İkincisi başarısız olursa ROLLBACK ilk değişikliği de geri alır — sanki hiçbir şey olmamış gibi. Sonuç: veritabanı asla "yarım" bir durumda kalmaz.
Alıştırma
12 dkİşlem tasarla:
- Para transferinin neden tek bir işlem olması gerektiğini açıkla.
- Bir adım başarısız olursa ne yapılmalı (COMMIT mi ROLLBACK mı)?
- Çok adımlı bir işlemi BEGIN/COMMIT/ROLLBACK ile sözde-yaz.
Bölüm 23
Görünümler (Views)
Sık kullanılan karmaşık bir sorguyu her seferinde yeniden yazmak yerine, onu bir görünüm (view) olarak kaydedebilirsin. Görünüm, kayıtlı bir sorgudur; ona basit bir tablo gibi SELECT atarsın.
Görünüm ne işe yarar?
- Karmaşık bir sorguyu bir isimle "paketler".
- Tekrar tekrar yazmak yerine basitçe
SELECT * FROM view. - Kullanıcılardan karmaşıklığı ve bazı sütunları gizleyebilir.
Görünümler, Modül 6'daki soyutlama fikrinin veritabanı karşılığıdır: karmaşık mantığı bir kez yaz, anlamlı bir isim ver, sonra o ismi defalarca kullan. Ek bir fayda: bir görünüm yalnızca belirli sütunları gösterecek şekilde tanımlanabilir, böylece bazı kullanıcılara hassas sütunları (örn. maaş) göstermeden veriye erişim verebilirsin. Görünümler genelde veriyi kopyalamaz; her erişimde alttaki sorgu yeniden çalışır.
Sorgu ne döndürür?
Sonuçaktif_musteriler görünümü, arkada karmaşık bir JOIN ve filtre sorgusu çalıştırır; ama sen ona SELECT * FROM aktif_musteriler diyerek basit bir tablo gibi erişirsin. Karmaşıklık bir kez yazılır ve isim ardına gizlenir — kod hem kısalır hem okunur.
Alıştırma
10 dkGörünüm düşün:
- Hangi karmaşık sorgunu bir görünüm yapardın? Neden?
- Görünümün soyutlama ile ilişkisini açıkla.
- Görünümün hassas sütunları gizlemede nasıl yardımcı olduğunu yaz.
Bölüm 24
Yedekleme ve Kurtarma
Veri, çoğu sistemin en değerli varlığıdır — ve donanım arızası, hatalı bir DELETE veya saldırı bir anda yok edebilir. Düzenli yedekleme, "felaket" anında veriyi geri getirmenin tek güvencesidir.
Yedekleme ilkeleri
- Düzenli ve otomatik: elle değil, zamanlanmış yedek.
- Birden çok kopya: farklı yerlerde (yerel + uzak).
- Geri yüklemeyi test et: denenmemiş yedek, yedek sayılmaz.
Altın kural 3-2-1: en az 3 kopya, 2 farklı ortamda, 1'i fiziksel olarak başka bir yerde (uzak/bulut). En sık yapılan hata, yedek almak ama geri yüklemeyi hiç test etmemektir — bozuk veya eksik bir yedeğin değeri sıfırdır. Bölüm 10-11'deki WHERE'siz UPDATE/DELETE felaketlerinden kurtulmanın son çaresi de iyi bir yedektir. Yedekleme bir maliyet değil, sigortadır.
Sorgu ne döndürür?
Sonuçİyi bir yedekleme düzeninde, veritabanı düzenli aralıklarla otomatik olarak kopyalanır ve kopyalar farklı yerlerde saklanır. Bir felaket anında (örn. yanlışlıkla silinen tablo), en son sağlam yedekten geri yükleyerek veriyi kurtarırsın — yeter ki o yedeğin çalıştığını önceden test etmiş ol.
Alıştırma
8 dkYedekleme planla:
- Bir uygulama için yedekleme sıklığını ve yerlerini belirle.
- 3-2-1 kuralını kendi planında uygula.
- "Geri yüklemeyi test etmek" neden bu kadar önemli, açıkla.
Bölüm 25
NoSQL'e Kısa Bakış
İlişkisel veritabanları (SQL) çoğu iş için harikadır; ama bazı durumlar farklı yaklaşımlar gerektirir. NoSQL veritabanları, esneklik ve ölçek için tabloların yerine farklı veri modelleri (belge, anahtar-değer) kullanır.
SQL ve NoSQL
- SQL (ilişkisel): tablolar, katı şema, güçlü ilişkiler ve JOIN.
- NoSQL (belge/anahtar-değer): esnek yapı, kolay ölçek, JOIN az.
- Çoğu projede SQL yeterli ve daha güvenlidir; NoSQL belirli ihtiyaçlar için.
"NoSQL daha yeni, o yüzden daha iyi" düşüncesi yaygın bir yanılgıdır. İkisi de güçlüdür ama farklı işler için: katı ilişkiler ve tutarlılık gerektiren çoğu iş uygulaması (e-ticaret, finans, kayıt sistemleri) için SQL hâlâ ilk tercihtir. NoSQL ise çok büyük ölçek, esnek/değişken şema veya basit anahtar-değer erişimi gerektiren senaryolarda parlar. Seçim "moda"ya değil, probleme göre yapılır — Backend modülündeki mimari dersiyle aynı ilke.
Sorgu ne döndürür?
SonuçSQL'de veri katı tablolara ve ilişkilere göre düzenlenir; NoSQL'de ise (örneğin belge tabanlı bir veritabanında) bir kayıt, JSON benzeri esnek bir belge olabilir. İlişkiler ve tutarlılık önemliyse SQL, esneklik ve büyük ölçek önemliyse NoSQL öne çıkar — ama bu modülde öğrendiğin temeller her iki dünyada da işine yarar.
Alıştırma
10 dkKarşılaştır:
- Bir bankacılık sistemi için SQL mi NoSQL mi? Gerekçeni yaz.
- NoSQL'in bir avantajını ve bir dezavantajını söyle.
- Seçimin "moda" değil "problem" temelli olması gerektiğini açıkla.
Bölüm 26
Bitirme: Küçük Bir Şema Tasarlamak
Tüm öğrendiklerini birleştirip baştan sona küçük bir veritabanı tasarlıyorsun: tablolar, anahtarlar, ilişkiler ve birkaç temel sorgu. Bu, gerçek bir projenin veri katmanının çekirdeğidir.
Örnek: basit bir blog şeması
Şema + örnek sorgular
-- Tasarım kontrol listesi:
-- 1. Varlıklar: yazarlar, yazilar (her biri bir tablo)
-- 2. Birincil anahtarlar: id (PK)
-- 3. İlişki: yazilar.yazar_id -> yazarlar.id (FK)
-- 4. Normalize: yazar bilgisi tek yerde
-- Her yazıyı yazar adıyla getir:
SELECT yazilar.baslik, yazarlar.ad
FROM yazilar
INNER JOIN yazarlar ON yazilar.yazar_id = yazarlar.id;Gerçek bir şema tasarlarken bu sırayı izle: varlıkları belirle → her birini tablo yap → birincil anahtarları koy → ilişkileri yabancı anahtarlarla kur → normalize et (tekrarı önle) → sık aranan sütunlara indeks ekle → güvenliği (parametreli sorgular) baştan düşün. Bu modülü tamamladıysan, artık verinin nasıl saklandığını ve sorgulandığını biliyorsun. Sıradaki adım, bu veritabanına gerçek bir dille (PHP, Python, C#) bağlanıp uygulamanı hayata geçirmek.
Sorgu ne döndürür?
SonuçTasarladığın blog şemasında her yazı bir yazar_id ile bir yazara bağlıdır. Yukarıdaki JOIN, her yazıyı yazarının adıyla birlikte tek bir sonuçta döner. Tablolar, anahtarlar, ilişki ve sorgu bir araya gelince — çalışan, tutarlı ve büyümeye hazır bir veri katmanın olur.
Alıştırma
20 dkŞemanı tasarla:
- Bir "etkinlik kayıt" sistemi seç; varlıklarını belirle.
- Tabloları, birincil ve yabancı anahtarlarıyla tasarla.
- İki tabloyu birleştiren bir JOIN sorgusu yaz.
- Güvenlik (parametreli sorgu) ve bir indeks kararını tasarıma ekle.
Ek
SQL & Veritabanı Terimleri Sözlüğü
En sık kullanılan SQL komutları ve veritabanı terimleri. Bir başvuru kaynağı olarak saklayabilirsin.
SQL'in özeti
SonuçSQL ile veriyi dört temel işlemle yönetirsin: SELECT (oku), INSERT (ekle), UPDATE (güncelle), DELETE (sil). Tabloları birincil anahtar ile tanımlar, yabancı anahtar ve JOIN ile ilişkilendirir, GROUP BY ile özetlersin. Güvenliğin altın kuralı: kullanıcı verisini sorguya gömme, her zaman parametreli sorgu kullan — böylece SQL enjeksiyonundan korunursun.