---
title: 'Normal Formlar'
source: 'https://academia.sh/tr/kurslar/iliskisel-kuram/normal-formlar'
course: 'Veri Modelleme ve İlişkisel Kuram'
language: tr
updated: '2026-08-17T18:09:00+00:00'
license: 'CC BY-SA 4.0'
---

# Normal Formlar

Güncelleme anomalilerinin üç türü; birinci, ikinci ve üçüncü normal formun tanımı; her basamağın hangi anomaliyi kaldırdığının sorgu çıktısıyla gösterimi.

Önceki ders tekrarın kaynağını adlandırdı: sol tarafı anahtar olmayan işlevsel
bağımlılıklar. Bu dersin sorusu şudur: bu bağımlılıklar hangi sırayla giderilir, ve her
adım hangi somut sorunu ortadan kaldırır?

Normalizasyonun ölçütü estetik değildir. Ölçüt, **güncelleme anomalileridir** (update
anomalies): bir bağıntının yapısı yüzünden ortaya çıkan, veriyi tutarsız bırakan
durumlar. Üç türü vardır.

- **Ekleme anomalisi** (insertion anomaly): bir olguyu kaydetmek için ilgisiz başka bir
  olgunun da bilinmesi gerekir. Henüz hiç ödünç verilmemiş bir şube, ödünç kayıtlarının
  tutulduğu tabloya yazılamaz.
- **Silme anomalisi** (deletion anomaly): bir olgu silinirken ikinci bir olgu da
  kaybolur. Bir kitabın tek ödünç kaydı silindiğinde kitabın kendisi de kayıtlardan çıkar.
- **Güncelleme anomalisi** (modification anomaly): aynı olgu birden çok satırda yazılı
  olduğu için değişiklik hepsine uygulanmalıdır; biri atlanırsa veri kendi içinde çelişir.

Normal formlar, bu üç anomaliyi doğuran yapıları basamak basamak eleyen tanımlardır.

## Birinci Normal Form

**Birinci normal form** (first normal form), her satır–sütun kesişiminde tek ve bölünmez
bir değer bulunmasını ister. Liste, iç içe yapı ya da tekrarlanan sütun grubu bulunmaz.

Kuralın bedeli somuttur. Telefon numaraları tek bir metin sütununda virgülle ayrılmış
tutulduğunda, bir numarayı aramak dizgi eşlemesine döner ve dizgi eşlemesi yanlış eşleşir:

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode box
CREATE TABLE uye_duz (uye_no INTEGER PRIMARY KEY, ad TEXT, telefonlar TEXT);
INSERT INTO uye_duz VALUES (41, 'Ayse Demir',   '0312-555-0101,0312-555-0102'),
                           (52, 'Mert Kaya',    '0312-555-0110'),
                           (63, 'Selin Ozturk', '0312-555-011');

CREATE TABLE uye_telefon (uye_no INTEGER, telefon TEXT, PRIMARY KEY (uye_no, telefon));
INSERT INTO uye_telefon VALUES (41, '0312-555-0101'), (41, '0312-555-0102'),
                               (52, '0312-555-0110'), (63, '0312-555-011');

SELECT 'tek sutunda liste' AS yazim, COUNT(*) AS bulunan
  FROM uye_duz WHERE telefonlar LIKE '%0312-555-011%'
UNION ALL
SELECT 'ayri bagintida', COUNT(*)
  FROM uye_telefon WHERE telefon = '0312-555-011';
SQL
```

```
┌───────────────────┬─────────┐
│       yazim       │ bulunan │
├───────────────────┼─────────┤
│ tek sutunda liste │ 2       │
│ ayri bagintida    │ 1       │
└───────────────────┴─────────┘
```

Aranan numara `0312-555-011` idi ve tek sahibi vardı. Dizgi araması, o numarayı önek
olarak içeren `0312-555-0110` kaydını da getirdi. Numaralar ayrı bir bağıntıda tutulduğunda
karşılaştırma eşitlik olur ve yanlış eşleşme kalkar; ayrıca numaraya kısıt yazılabilir,
tekilliği denetlenebilir ve tek bir numara silinebilir.

Aynı kural "tekrarlanan sütun grubu" biçimi için de geçerlidir. `telefon_1`, `telefon_2`,
`telefon_3` sütunları listeyi yatay yazmaktan başka bir şey değildir; dördüncü numara
geldiğinde şema değişikliği gerektirir.

## İkinci Normal Form

**İkinci normal form** (second normal form) birinci normal formu sağlayan ve **anahtar
dışı hiçbir özniteliğin aday anahtarın öz alt kümesine bağımlı olmadığı** bağıntıyı
tanımlar. Kısacası kısmi bağımlılık bulunmaz. Tanım yalnızca bileşik anahtarlı
bağıntılarda anlam taşır; tek sütunluk anahtarda öz alt küme yoktur.

Her şubedeki kitap adedini tutan bağıntının anahtarı `(isbn, sube_kodu)` çiftidir. Kitabın
başlığı yalnız ISBN'e, şubenin adı yalnız şube koduna bağlıdır — ikisi de kısmi
bağımlılıktır:

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode box
CREATE TABLE stok_duz (
  isbn         TEXT    NOT NULL,
  sube_kodu    TEXT    NOT NULL,
  adet         INTEGER NOT NULL,
  kitap_baslik TEXT    NOT NULL,
  sube_ad      TEXT    NOT NULL,
  PRIMARY KEY (isbn, sube_kodu)
);
INSERT INTO stok_duz VALUES
  ('975-01', 'MRK', 3, 'Kayip Zaman',     'Merkez'),
  ('975-01', 'BHC', 1, 'Kayip Zaman',     'Bahcelievler'),
  ('975-02', 'MRK', 2, 'Deniz Fenerleri', 'Merkez'),
  ('975-02', 'BHC', 4, 'Deniz Fenerleri', 'Bahcelievler'),
  ('975-03', 'BHC', 1, 'Sessiz Bahce',    'Bahcelievler');

UPDATE stok_duz SET sube_ad = 'Bahcelievler Subesi'
 WHERE sube_kodu = 'BHC' AND isbn = '975-01';

SELECT sube_kodu, COUNT(*) AS satir, COUNT(DISTINCT sube_ad) AS farkli_ad
FROM stok_duz GROUP BY sube_kodu;
SQL
```

```
┌───────────┬───────┬───────────┐
│ sube_kodu │ satir │ farkli_ad │
├───────────┼───────┼───────────┤
│ BHC       │ 3     │ 2         │
│ MRK       │ 2     │ 1         │
└───────────┴───────┴───────────┘
```

Şube adını değiştiren güncelleme bir satıra uygulandı ve şube artık iki farklı adla
kayıtlı. Motor bunu engelleyemez, çünkü "aynı şube kodunun aynı adı taşıması" kuralı
şemada yazılı değildir — yazılamaz da, bağımlılığın sol tarafı anahtar değildir.

Ayrıştırma, kısmi bağımlılığın sol tarafını kendi bağıntısının anahtarı yapar: kitap
bilgisi `kitap` bağıntısına, şube bilgisi `sube` bağıntısına taşınır, `stok` yalnız
anahtar ile ona tam bağımlı `adet` sütununu tutar.

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode box
PRAGMA foreign_keys = ON;
CREATE TABLE kitap (isbn TEXT PRIMARY KEY NOT NULL, baslik TEXT NOT NULL);
CREATE TABLE sube  (sube_kodu TEXT PRIMARY KEY NOT NULL, ad TEXT NOT NULL);
CREATE TABLE stok  (
  isbn      TEXT    NOT NULL REFERENCES kitap (isbn),
  sube_kodu TEXT    NOT NULL REFERENCES sube (sube_kodu),
  adet      INTEGER NOT NULL,
  PRIMARY KEY (isbn, sube_kodu)
);
INSERT INTO kitap VALUES ('975-01', 'Kayip Zaman'), ('975-02', 'Deniz Fenerleri'),
                         ('975-03', 'Sessiz Bahce');
INSERT INTO sube  VALUES ('MRK', 'Merkez'), ('BHC', 'Bahcelievler'), ('KDK', 'Kadikoy');
INSERT INTO stok  VALUES ('975-01', 'MRK', 3), ('975-01', 'BHC', 1), ('975-02', 'MRK', 2),
                         ('975-02', 'BHC', 4), ('975-03', 'BHC', 1);

UPDATE sube SET ad = 'Bahcelievler Subesi' WHERE sube_kodu = 'BHC';

SELECT changes() AS guncellenen_satir,
       (SELECT COUNT(*) FROM sube WHERE sube_kodu = 'KDK') AS stoksuz_sube;
SQL
```

```
┌───────────────────┬──────────────┐
│ guncellenen_satir │ stoksuz_sube │
├───────────────────┼──────────────┤
│ 1                 │ 1            │
└───────────────────┴──────────────┘
```

Şube adı tek bir satırda tutulduğu için tek güncelleme yeter ve tutarsızlık kurulamaz.
Aynı ayrıştırma ekleme anomalisini de kaldırır: hiç kitabı bulunmayan Kadıköy şubesi
kayıtlıdır — düz tabloda bu satır yazılamazdı, çünkü anahtarın ISBN parçası boş kalırdı.
Değişen satır sayısını veren işlevin adı motora göre değişir.

## Üçüncü Normal Form

**Üçüncü normal form** (third normal form) ikinci normal formu sağlayan ve **anahtar dışı
hiçbir özniteliğin başka bir anahtar dışı özniteliğe bağımlı olmadığı** bağıntıyı
tanımlar. Kısacası geçişli bağımlılık bulunmaz.

Ödünç kaydında anahtar tek sütundur, dolayısıyla kısmi bağımlılık yoktur; buna karşılık
`odunc_no → uye_no → uye_ad, uye_eposta` zinciri vardır. Üye bilgisi ödünç işlemine
doğrudan değil, üye numarası üzerinden bağlıdır:

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode box
CREATE TABLE odunc_duz (
  odunc_no     INTEGER PRIMARY KEY,
  uye_no       INTEGER NOT NULL,
  uye_ad       TEXT    NOT NULL,
  uye_eposta   TEXT    NOT NULL,
  isbn         TEXT    NOT NULL,
  kitap_baslik TEXT    NOT NULL,
  alis_tarihi  TEXT    NOT NULL
);
INSERT INTO odunc_duz VALUES
  (1001, 41, 'Ayse Demir', 'ayse@ornek.org', '975-01', 'Kayip Zaman',     '2025-03-02'),
  (1002, 52, 'Mert Kaya',  'mert@ornek.org', '975-01', 'Kayip Zaman',     '2025-03-04'),
  (1003, 41, 'Ayse Demir', 'ayse@ornek.org', '975-02', 'Deniz Fenerleri', '2025-03-05'),
  (1004, 41, 'Ayse Demir', 'ayse@ornek.org', '975-01', 'Kayip Zaman',     '2025-03-20'),
  (1005, 52, 'Mert Kaya',  'mert@ornek.org', '975-03', 'Sessiz Bahce',    '2025-03-22');

UPDATE odunc_duz SET uye_eposta = 'ayse.demir@ornek.org' WHERE odunc_no = 1001;
DELETE FROM odunc_duz WHERE odunc_no = 1005;

SELECT (SELECT COUNT(DISTINCT uye_eposta) FROM odunc_duz WHERE uye_no = 41) AS uye41_eposta,
       (SELECT COUNT(*) FROM odunc_duz WHERE isbn = '975-03')               AS kitap975_03;
SQL
```

```
┌──────────────┬─────────────┐
│ uye41_eposta │ kitap975_03 │
├──────────────┼─────────────┤
│ 2            │ 0           │
└──────────────┴─────────────┘
```

İki anomali aynı anda görünür. Bir satırda düzeltilen e-posta adresi, aynı üyenin iki
farklı adrese sahip görünmesine yol açtı. Tek ödünç kaydı silinen kitap ise veritabanından
tamamen kayboldu — başlığı yalnız o satırda yazılıydı.

Ayrıştırma, geçişli zincirin ortasını kendi bağıntısının anahtarı yapar:

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode box
PRAGMA foreign_keys = ON;
CREATE TABLE uye   (uye_no INTEGER PRIMARY KEY, ad TEXT NOT NULL, eposta TEXT NOT NULL);
CREATE TABLE kitap (isbn TEXT PRIMARY KEY NOT NULL, baslik TEXT NOT NULL);
CREATE TABLE odunc (
  odunc_no    INTEGER PRIMARY KEY,
  uye_no      INTEGER NOT NULL REFERENCES uye (uye_no),
  isbn        TEXT    NOT NULL REFERENCES kitap (isbn),
  alis_tarihi TEXT    NOT NULL
);
INSERT INTO uye   VALUES (41, 'Ayse Demir', 'ayse@ornek.org'),
                         (52, 'Mert Kaya',  'mert@ornek.org');
INSERT INTO kitap VALUES ('975-01', 'Kayip Zaman'), ('975-02', 'Deniz Fenerleri'),
                         ('975-03', 'Sessiz Bahce');
INSERT INTO odunc VALUES (1001, 41, '975-01', '2025-03-02'), (1002, 52, '975-01', '2025-03-04'),
                         (1003, 41, '975-02', '2025-03-05'), (1004, 41, '975-01', '2025-03-20'),
                         (1005, 52, '975-03', '2025-03-22');

UPDATE uye SET eposta = 'ayse.demir@ornek.org' WHERE uye_no = 41;
DELETE FROM odunc WHERE odunc_no = 1005;

SELECT (SELECT COUNT(DISTINCT eposta) FROM uye WHERE uye_no = 41) AS uye41_eposta,
       (SELECT COUNT(*) FROM kitap WHERE isbn = '975-03')         AS kitap975_03;
SQL
```

```
┌──────────────┬─────────────┐
│ uye41_eposta │ kitap975_03 │
├──────────────┼─────────────┤
│ 1            │ 1           │
└──────────────┴─────────────┘
```

Aynı iki deyim çalıştırıldı; sonuç değişti. E-posta tek yerde tutulduğu için tek adres
kaldı, kitap kaydı ödünç kaydından bağımsız olduğu için silmeden etkilenmedi. İkisi de
sorgu yazımıyla değil, şema yapısıyla sağlandı.

## Ayrıştırmanın İki Koşulu

Bağıntı bölmek her zaman güvenli değildir. İki koşul aranır.

**Kayıpsız birleştirme** (lossless join): ayrılan bağıntılar yeniden birleştirildiğinde
başlangıçtaki satırlar aynen elde edilmeli, fazladan satır doğmamalıdır. Koşul şudur:
ortak öznitelik kümesi, parçalardan en az birinin süperanahtarı olmalıdır. Yukarıdaki
ayrıştırmaların hepsi bunu sağlar, çünkü bölme her zaman bir bağımlılığın sol tarafından
yapıldı.

**Bağımlılık koruma** (dependency preservation): başlangıçtaki bağımlılıklar, parçalar
üzerinde ayrı ayrı denetlenebilmelidir. Korunmayan bir bağımlılık, ancak parçaları
birleştirerek sınanabilir — yani kısıt olarak yazılamaz.

Üçüncü normal forma kadar olan ayrıştırmalarda ikisi de birlikte sağlanabilir. Sıradaki
dersin konusu, bu iki koşulun ayrıştığı durumdur.

## Özet

- Normalizasyonun ölçütü ekleme, silme ve güncelleme anomalilerinin ortadan kalkmasıdır.
- Birinci normal form her hücrede tek bölünmez değer ister; liste tutan sütun, aramayı
  dizgi eşlemesine indirger ve yanlış eşleşme üretir.
- İkinci normal form kısmi bağımlılığı, üçüncü normal form geçişli bağımlılığı kaldırır;
  ikisi de bölmeyi bağımlılığın sol tarafından yapar.
- Normalleştirilmiş şemada bir olgu tek yerde yazılıdır; güncelleme tek satıra uygulanır
  ve tutarsızlık kurulamaz.
- Ayrıştırma kayıpsız birleştirme ve bağımlılık koruma koşullarını sağlamalıdır; ortak
  öznitelik kümesi parçalardan birinin süperanahtarı olduğunda birleştirme kayıpsızdır.

## Sonraki Adım

Üçüncü normal form, anahtar dışı özniteliklere odaklanır. Peki bağımlılığın sağ tarafı
anahtarın bir parçasıysa? Tanım gereği o öznitelik anahtar dışı değildir ve üçüncü normal
form ihlal edilmiş sayılmaz — ama tekrar sürer. Sıradaki ders bu boşluğu kapatan
Boyce–Codd normal formunu tanımlar, kayıpsız birleştirme ile bağımlılık korumanın birlikte
sağlanamadığı durumu gösterir ve çok değerli bağımlılıkla dördüncü normal forma geçer.
