---
title: 'Şema Değiştirme'
source: 'https://academia.sh/tr/kurslar/sql-temelleri/sema-degistirme'
course: 'SQL Temelleri'
language: tr
updated: '2026-08-17T18:09:01+00:00'
license: 'CC BY-SA 4.0'
---

# Şema Değiştirme

ALTER TABLE ile sütun ekleme, adlandırma ve kaldırma; tek deyimle yapılamayan değişikliklerin motora göre değişen sınırı ve tabloyu taşınabilir biçimde yeniden kurma yordamı.

Önceki ders şemayı kısıtlarıyla birlikte yazdı. Gerçek bir şema ise ilk yazıldığı hâlde
kalmaz: üyelere telefon alanı gerekir, bir sütunun adı yanlış seçilmiştir, e-posta alanına
sonradan bir kısıt eklenmek istenir. Üstelik bunlar tablo boşken değil, içinde veri
varken yapılır.

`ALTER TABLE` deyimi bu değişiklikleri yazar. Deyimin kendisi standarttır, ancak
**hangi değişikliği tek deyimde yapabildiği motora göre değişir** — SQL'de taşınabilirliğin
en zayıf olduğu alanlardan biridir. Bu ders hem deyimi hem de sınırı gösterir, sonra
sınırın ötesine geçmenin her motorda çalışan yolunu kurar.

## Sütun Eklemek ve Yeniden Adlandırmak

En çok gereken iki değişiklik en ucuz olanlardır: sonuna sütun eklemek ve bir sütunun
adını değiştirmek. Her ikisi de var olan satırların içeriğine dokunmadan yapılabilir.

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE uye (
  uye_id       INTEGER PRIMARY KEY,
  ad           TEXT NOT NULL,
  soyad        TEXT NOT NULL,
  eposta       TEXT UNIQUE,
  kayit_tarihi TEXT NOT NULL
);
INSERT INTO uye VALUES (1,'Ayşe','Demir','ayse@ornek.test','2023-02-14'),
                       (3,'Zeynep','Arslan',NULL,'2024-01-09');

ALTER TABLE uye ADD COLUMN telefon TEXT;
ALTER TABLE uye ADD COLUMN bildirim TEXT NOT NULL DEFAULT 'eposta';
ALTER TABLE uye RENAME COLUMN kayit_tarihi TO uyelik_tarihi;

SELECT * FROM uye;
SQL
```

```
uye_id  ad      soyad   eposta           uyelik_tarihi  telefon  bildirim
------  ------  ------  ---------------  -------------  -------  --------
1       Ayşe    Demir   ayse@ornek.test  2023-02-14              eposta  
3       Zeynep  Arslan                   2024-01-09              eposta  
```

Var olan iki satır yeni sütunları da aldı. `telefon` sütununda değer yok, çünkü kısıt da
varsayılan da yazılmadı: eski satırlar boş değer taşır. `bildirim` sütununda ise `NOT NULL`
kısıtı var, dolayısıyla boşluk kabul edilemez — motor eski satırları varsayılan değerle
doldurdu. Sütun eklerken bu iki durumdan biri seçilmelidir: ya sütun boş kalabilir ya da
eski satırların ne alacağı yazılır.

`RENAME COLUMN` yalnızca adı değiştirir; veriye ve kısıtlara dokunmaz. Bu, görünüşte
zararsız ama etkisi geniş bir işlemdir: sütunun eski adını kullanan her sorgu, her
görünüm ve her uygulama kodu kırılır. Adlandırma hatası fark edildiğinde düzeltmek
ucuzdur, aylar sonra düzeltmek değildir.

Bu dersteki blokların her biri kendi başına çalışır ve üye tablosunun yalnızca örneğe
gereken sütunlarını kurar; kursun asıl şeması önceki derste yazılan tanımdır. Yukarıdaki
yeniden adlandırma da o tanıma işlenmez, etkisini göstermek için yapılmıştır — sonraki
derslerde sütunun adı `kayit_tarihi` olarak sürer.

## Eklemenin Sınırları

Sütun eklemek her zaman ucuz değildir. Ucuz olmasının nedeni, motorun var olan satırlara
dokunmak zorunda kalmamasıdır. Bu koşulun bozulduğu üç durum vardır ve motor bunları
reddeder.

```sh
sqlite3 :memory: <<'SQL'
CREATE TABLE uye (
  uye_id       INTEGER PRIMARY KEY,
  ad           TEXT NOT NULL,
  soyad        TEXT NOT NULL,
  eposta       TEXT UNIQUE,
  kayit_tarihi TEXT NOT NULL
);
INSERT INTO uye VALUES (1,'Ayşe','Demir','ayse@ornek.test','2023-02-14');

ALTER TABLE uye ADD COLUMN kimlik_no TEXT NOT NULL;
ALTER TABLE uye ADD COLUMN kart_no TEXT UNIQUE;
ALTER TABLE uye ADD COLUMN son_giris TEXT DEFAULT (date('now'));
SQL
```

```
Runtime error near line 10: Cannot add a NOT NULL column with default value NULL
Parse error near line 11: Cannot add a UNIQUE column
Runtime error near line 12: Cannot add a column with non-constant default
```

Üç ret, üç ayrı gerekçeyle gelir. Birincisi, varsayılanı olmayan zorunlu sütundur: var
olan satırın o sütunda ne yazacağı belirsizdir, boş bırakılamaz da. İkincisi benzersizlik
kısıtıdır: yeni sütun bütün satırlarda aynı değeri — boşluğu ya da varsayılanı — taşıyacağı
için kısıt daha kurulurken ihlal edilebilir. Üçüncüsü sabit olmayan varsayılandır: değeri
her satır için ayrı hesaplanan bir varsayılan, eski satırlara ne yazılacağını belirsiz
bırakır.

Bu üç iletinin sözcükleri motora özgüdür. Ortak olan kural şudur: **var olan satırların
yeniden yazılmasını gerektiren bir ekleme tek deyimle yapılamaz.** Sütun önce boş
bırakılabilir hâlde eklenir, satırlar doldurulur, kısıt sonra kurulur.

## Sütun Kaldırmak

Sütun kaldırmak da benzer bir sınıra takılır. İşlemin kendisi tanımlıdır, ancak
kaldırılacak sütun bir kısıtın ya da dizinin parçasıysa reddedilir.

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE uye (
  uye_id       INTEGER PRIMARY KEY,
  ad           TEXT NOT NULL,
  soyad        TEXT NOT NULL,
  eposta       TEXT UNIQUE,
  kayit_tarihi TEXT NOT NULL,
  telefon      TEXT
);
INSERT INTO uye VALUES (1,'Ayşe','Demir','ayse@ornek.test','2023-02-14','0312 000 00 00');

ALTER TABLE uye DROP COLUMN telefon;
SELECT * FROM uye;
ALTER TABLE uye DROP COLUMN eposta;
SQL
```

```
uye_id  ad    soyad  eposta           kayit_tarihi
------  ----  -----  ---------------  ------------
1       Ayşe  Demir  ayse@ornek.test  2023-02-14  
Parse error near line 15: cannot drop UNIQUE column: "eposta"
```

Kısıtsız `telefon` sütunu kalktı; benzersizlik kısıtı taşıyan `eposta` kalkmadı. Sütun
kaldırmanın geri alınamaz olduğunu da not etmek gerekir: sütunla birlikte içindeki bütün
değerler gider. Üretimdeki bir tabloda sütun kaldırmadan önce yapılan iş, sütunu
kullanmayı bırakıp bir süre beklemektir; kaldırma en son adımdır.

## Tabloyu Yeniden Adlandırmak

Tablo adı değiştiğinde, o tabloya başvuran yabancı anahtarların ne olacağı ayrı bir
sorudur. Kullanılan motor başvuruları izler ve günceller.

```sh
sqlite3 :memory: <<'SQL'
PRAGMA foreign_keys = ON;

CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL);
CREATE TABLE kitap (
  kitap_id INTEGER PRIMARY KEY,
  baslik   TEXT NOT NULL,
  yazar    TEXT NOT NULL,
  sube_id  INTEGER REFERENCES sube(sube_id)
);

ALTER TABLE sube RENAME TO subeler;
.schema kitap
SQL
```

```
CREATE TABLE kitap (
  kitap_id INTEGER PRIMARY KEY,
  baslik   TEXT NOT NULL,
  yazar    TEXT NOT NULL,
  sube_id  INTEGER REFERENCES "subeler"(sube_id)
);
```

`kitap` tablosunun tanımı, ona hiç dokunulmadığı hâlde değişti. Bu davranış motora göre
değişir: kimi motorlar başvuruyu izler, kimileri eski adı tutmayı sürdürür ve şema
tutarsız kalır. Tablo adı değiştirmenin öncesinde, o tabloya kimin başvurduğu
çıkarılmalıdır.

## Tabloyu Yeniden Kurmak

Bir sütunun tipini değiştirmek, var olan bir sütuna kısıt eklemek, bir kısıtı kaldırmak
ya da sütun sırasını düzeltmek — bunların hiçbiri kullanılan motorda tek deyimle
yapılamaz. Kimi motorlarda bir kısmı yapılabilir, ancak yapılabildiği yerde bile tablo
büyükse işlem satırları yeniden yazar.

Her motorda çalışan yol, tabloyu yeniden kurmaktır. Yordam dört adımdır: istenen tanımla
yeni bir tablo yaratılır, veri kopyalanır, eski tablo düşürülür, yeni tablo eski adı alır.
Dördü tek bir işlemin içinde yapılır ki yarıda kalan bir adım şemayı bozuk bırakmasın.

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode column
PRAGMA foreign_keys = OFF;

CREATE TABLE uye (
  uye_id       INTEGER PRIMARY KEY,
  ad           TEXT NOT NULL,
  soyad        TEXT NOT NULL,
  eposta       TEXT UNIQUE,
  kayit_tarihi TEXT NOT NULL,
  durum        TEXT NOT NULL DEFAULT 'etkin'
                 CHECK (durum IN ('etkin', 'askida', 'kapali')),
  bildirim     TEXT NOT NULL DEFAULT 'eposta'
);
INSERT INTO uye (uye_id, ad, soyad, eposta, kayit_tarihi) VALUES
  (1,'Ayşe','Demir','ayse@ornek.test','2023-02-14'),
  (3,'Zeynep','Arslan',NULL,'2024-01-09');

BEGIN;

CREATE TABLE uye_yeni (
  uye_id       INTEGER PRIMARY KEY,
  ad           TEXT NOT NULL,
  soyad        TEXT NOT NULL,
  eposta       TEXT UNIQUE CHECK (eposta IS NULL OR eposta LIKE '%@%'),
  kayit_tarihi TEXT NOT NULL,
  durum        TEXT NOT NULL DEFAULT 'etkin'
                 CHECK (durum IN ('etkin', 'askida', 'kapali')),
  bildirim     TEXT NOT NULL DEFAULT 'eposta'
                 CHECK (bildirim IN ('eposta', 'sms', 'yok'))
);

INSERT INTO uye_yeni (uye_id, ad, soyad, eposta, kayit_tarihi, durum, bildirim)
SELECT uye_id, ad, soyad, eposta, kayit_tarihi, durum, bildirim FROM uye;

DROP TABLE uye;
ALTER TABLE uye_yeni RENAME TO uye;

COMMIT;

PRAGMA foreign_key_check;
SELECT * FROM uye;
SQL
```

```
uye_id  ad      soyad   eposta           kayit_tarihi  durum  bildirim
------  ------  ------  ---------------  ------------  -----  --------
1       Ayşe    Demir   ayse@ornek.test  2023-02-14    etkin  eposta  
3       Zeynep  Arslan                   2024-01-09    etkin  eposta  
```

Yeni tanımdaki iki denetim koşulu da `ALTER TABLE` ile eklenemezdi, çünkü ikisi de **var
olan** sütunlara bağlanıyor: biri `eposta`, diğeri dersin başında eklenen `bildirim`
sütunu. O sütun eklenirken varsayılan verilebilmişti ama kısıt verilememişti; kısıt
ancak burada, tablo yeniden kurulurken tanıma girdi. Veri korundu, iki satır da yeni
tanıma uydu — boş e-postalı satır dahil, çünkü koşul boşluğu ayrıca karşılıyor.

Kopyalama adımının bir yan yararı vardır: `SELECT` listesi yazıldığı için sütunlar
dönüştürülebilir. Bir tarih sütunu metinden sayıya çevriliyorsa dönüşüm burada yapılır;
eski sütun düşürülüyorsa listeye alınmaz.

Kopyalama sırasında yeni tanımın kısıtları uygulanır. Eski veri yeni kısıtı ihlal
ediyorsa deyim başarısız olur ve işlem geri alınır — istenen budur. Şema değişikliği,
veriyi kısıta uydurma işiyle birlikte planlanır.

`PRAGMA foreign_key_check` çağrısı hiçbir şey yazdırmadı: kırık başvuru yok. Bu çağrı
yordamın son adımıdır ve atlanmamalıdır.

## Yeniden Kurmanın Riski

Yabancı anahtar denetimi yordam boyunca kapatılır, çünkü `DROP TABLE` adımı ile
`RENAME TO` adımı arasında hedef tablo geçici olarak yoktur. Denetimin kapalı olması,
kopyalamada yapılan bir hatanın sessizce geçmesi demektir.

```sh
sqlite3 :memory: <<'SQL'
.headers on
.mode column
PRAGMA foreign_keys = OFF;

CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL);
CREATE TABLE kitap (
  kitap_id INTEGER PRIMARY KEY,
  baslik   TEXT NOT NULL,
  sube_id  INTEGER NOT NULL REFERENCES sube(sube_id)
);
INSERT INTO sube VALUES (1,'Merkez','Ankara'),(3,'Kadıköy','İstanbul');
INSERT INTO kitap VALUES (1,'Körlük',1),(5,'Sessiz Ev',3);

BEGIN;
CREATE TABLE sube_yeni (
  sube_id INTEGER PRIMARY KEY,
  ad      TEXT NOT NULL,
  sehir   TEXT NOT NULL,
  acik    INTEGER NOT NULL DEFAULT 1
);
INSERT INTO sube_yeni (sube_id, ad, sehir)
SELECT sube_id, ad, sehir FROM sube WHERE sehir = 'Ankara';
DROP TABLE sube;
ALTER TABLE sube_yeni RENAME TO sube;
COMMIT;

PRAGMA foreign_key_check;
SQL
```

```
table  rowid  parent  fkid
-----  -----  ------  ----
kitap  5      sube    0   
```

Kopyalama deyimindeki koşul yüzünden bir şube taşınmadı ve ona bağlı kitap öksüz kaldı.
İşlem başarıyla kesinleşti, hiçbir hata verilmedi; kırığı yalnızca denetim çağrısı
gösterdi. Yordamın bu son adımı, sessiz veri kaybının tek uyarısıdır.

Uygulamada üç alışkanlık bu riski küçültür. Yeniden kurma yordamı, üretim verisinin bir
kopyası üzerinde önce denenir. Kopyalama deyiminden sonra satır sayıları karşılaştırılır.
Ve yordam bir işlemin içinde çalıştırılır, böylece adımlardan biri başarısız olduğunda
şema eski hâline döner.

## Özet

- `ALTER TABLE` sütun ekleme, yeniden adlandırma ve kaldırmayı tek deyimde yapar; hangi
  değişikliğin desteklendiği motora göre değişir.
- Var olan satırların yeniden yazılmasını gerektiren eklemeler reddedilir: varsayılanı
  olmayan zorunlu sütun, benzersiz sütun ve sabit olmayan varsayılan.
- Sütun kaldırmak geri alınamaz ve kısıtın parçası olan sütunlarda reddedilir; güvenli
  sıra, önce kullanımı bırakmak sonra kaldırmaktır.
- Tek deyimle yapılamayan değişiklikler için taşınabilir yol tabloyu yeniden kurmaktır:
  yeni tablo, kopyalama, düşürme, yeniden adlandırma — hepsi tek işlem içinde.
- Yeniden kurma sırasında yabancı anahtar denetimi kapalı olduğu için, yordamın son adımı
  başvuru bütünlüğünü sınamaktır.

## Sonraki Adım

Şema kurulmuş ve değiştirilebilir durumda. Sıradaki soru, içine veriyi nasıl koyduğumuz.
Sonraki ders satır eklemeyi ele alır: tek satırlık ekleme, tek deyimde çok satır, sorgu
sonucunu doğrudan tabloya yazma ve bunların birbirinden ayrıldığı yer olan başarım.
Yirmi bin satırın tek tek mi yoksa tek işlem içinde mi eklendiği, ölçülebilir bir
farktır.
