Şemalar Değişir. SQLite de Buna Çoğunlukla İzin Verir.
Bir tablo oluşturduktan sonra er ya da geç onu yeniden adlandırmak, sütun eklemek, sütun kaldırmak ya da yapıyı baştan kurmak isteyeceksiniz. SQLite, sık karşılaşılan durumları DROP TABLE ve ALTER TABLE ile doğrudan destekler; geri kalanı için ise belgelenmiş bir geçici çözüm sunar.
Ama bir sorun var: SQLite'taki ALTER TABLE, Postgres ya da MySQL'dekine kıyasla oldukça kısıtlıdır. Neyi yapıp neyi yapamadığını bilmek — ve yapamadığı şeyler için tabloyu yeniden oluşturma yöntemini öğrenmek — bu konunun büyük kısmını oluşturur.
DROP TABLE: Tabloyu ve Ona Bağlı Her Şeyi Siler
SQLite'ta tablo silme işlemi DROP TABLE ile yapılır. Bu komut tabloyu, içindeki satırları, indeksleri ve tablo üzerinde tanımlı tetikleyicileri siler. Geri alma şansı yoktur:
Tablo artık yok. Bu noktada sorgu çalıştırmaya kalkarsanız no such table: scratch hatası alırsınız.
Tablonun var olup olmadığından emin değilseniz — özellikle kurulum scriptlerinde sık karşılaşılan bir durum — IF EXISTS kullanın; bu sayede tablo yoksa komut sessizce hiçbir şey yapmaz:
IF EXISTS olmadan ikinci DROP hata verirdi. Bu sayede ikisi de sorunsuz çalışıyor.
Foreign Key Kısıtlamaları DROP'u Engelleyebilir
Foreign key kontrolü açıksa (PRAGMA foreign_keys = ON;) ve sildiğiniz tabloya başka bir tablo referans veriyorsa, silme işlemi başarısız olur:
sqlite> PRAGMA foreign_keys = ON;
sqlite> DROP TABLE users;
Runtime error: FOREIGN KEY constraint failed
Birkaç seçeneğiniz var: önce referans veren tabloyu silebilir, referans veren satırları temizleyebilir ya da yabancı anahtarı oluştururken ON DELETE CASCADE ile tanımlayabilirsiniz. SQLite, referans bütünlüğünü sessiz sedasız bozmaz.
ALTER TABLE: Yapabildiği Dört Şey
SQLite'ta ALTER TABLE komutu yalnızca şu dört işlemi destekler:
Bu komutların her biri tek bir ifade olarak çalışır. İlk ikisi neredeyse bedavadır — yalnızca şemayı güncellerler. ADD COLUMN da hızlıdır: SQLite tabloyu baştan yazmaz, sadece yeni sütun tanımını kaydeder. DROP COLUMN ise daha ağır bir iştir, çünkü SQLite o sütunun verisini fiziksel olarak temizlemek için her satırı yeniden yazmak zorundadır.
ADD COLUMN ile Varsayılan Değer Verme
Mevcut bir tabloya eklediğiniz yeni bir sütun, varsayılan değer belirtmediğiniz sürece her satırda NULL olarak başlar:
Mevcut iki satıra da 'active' değeri yazılır. Varsayılan değerin sabit olması şart — SQLite, ADD COLUMN içinde CURRENT_TIMESTAMP veya sabit olmayan başka bir ifadeyi varsayılan olarak kabul etmez; çünkü her satır için ayrı ayrı hesaplamadan, mevcut tüm satırlara aynı değeri uygulayabilmesi gerekir.
Varsayılan değer olmadan NOT NULL bir sütun istiyorsanız, önce sütunu null kabul edecek şekilde eklemeniz, ardından UPDATE ile veriyi doldurmanız ve son olarak kısıtlamayı eklemek için tabloyu yeniden oluşturmanız gerekir. Bu da bizi sınırlamalara getiriyor.
SQLite ALTER TABLE Kısıtlamaları: Neler Yapılamaz?
Postgres veya MySQL'de sorunsuz çalışan ama SQLite'ta çalışmayan işlemler:
- Sütunun veri tipini değiştirmek (
ALTER COLUMN ... TYPE ...). - Sütunun varsayılan değerini yerinde değiştirmek.
- Mevcut bir sütuna
NOT NULL,CHECK,UNIQUEveyaPRIMARY KEYeklemek ya da kaldırmak. - Mevcut bir sütuna foreign key tanımlamak.
- Sütunların sırasını değiştirmek.
Bunlardan herhangi birini denediğinizde sözdizimi hatası alırsınız. SQLite'ta ALTER COLUMN diye bir ifade yok zaten. Resmi çözüm hepsi için aynı: tabloyu yeniden oluşturun.
SQLite Tablo Yeniden Oluşturma Yöntemi
ALTER TABLE ihtiyacınızı karşılayamadığında izlenen yol şu: istediğiniz şemaya sahip yeni bir tablo oluşturun, verileri ona kopyalayın, eski tabloyu silin ve yenisini onun adıyla yeniden adlandırın. İşlemi bir transaction içine alın ki ya tamamı çalışsın ya da hiçbiri uygulanmasın:
Artık users.age, check kısıtlamalı bir tam sayı; email ise NOT NULL. Veriler de bu sürece dahil olarak yeni tabloya taşındı.
Bunu gerçek bir projede yaparken aklında bulundurmanız gereken birkaç nokta var:
- Foreign key'leri geçici olarak kapat. Başka tablolar seninkine referans veriyorsa, transaction'dan önce
PRAGMA foreign_keys = OFF;, sonra daPRAGMA foreign_keys = ON;çalıştır. Aksi haldeDROP TABLEhata verir. Pragma transaction içinde değiştirilemediği için bunu mutlaka dışarıda ayarlamanız gerekiyor. - İndeksleri ve trigger'ları yeniden oluştur. Eski tabloyu sildiğinde indeksleri ve trigger'ları da gitmiş olur. Yeniden adlandırma işleminden sonra hepsini yeni tabloya tekrar eklemeniz lazım.
- View'ları kontrol et. Tabloya referans veren view'ların saklanan SQL'i hâlâ eski ismi gösterir. Değişen sütunlara bağlı olanları yeniden kurmanız gerekir.
Bu yeniden oluşturma yöntemi uzun ve yorucu görünse de güvenilir bir yaklaşım. Alembic veya Rails gibi migration araçları, SQLite hedeflediklerinde aslında perde arkasında tam olarak bunu yapıyor.
SQLite'ta Birden Fazla Tabloyu Silme
Birden fazla tabloyu tek bir ifadeyle silmenin bir yolu yok — her biri için ayrı ayrı DROP TABLE çalıştırmanız gerekiyor. Hepsini gruplayıp birlikte yürütmek istiyorsanız transaction içine alabilirsiniz:
Hepsini bir transaction içine sarmak, üç DROP işleminin ya tamamının başarılı olmasını ya da hiçbirinin gerçekleşmemesini sağlar — birbiriyle ilişkili tabloları kaldırırken yarı yolda foreign key hatasıyla karşılaşabileceğin durumlarda işine yarar.
Akılda Kalması Gerekenler
DROP TABLEbir tabloyu, ona ait index'leri ve trigger'ları siler. Tekrar tekrar çalıştırılabilir scriptler içinIF EXISTSkullan.ALTER TABLEyalnızca dört şey yapar: tabloyu yeniden adlandırma, sütunu yeniden adlandırma, sütun ekleme ve sütun silme.- Bunların dışında her şey için — tip değişiklikleri, yeni kısıtlamalar, mevcut sütunlara foreign key eklemek — tabloyu bir transaction içinde yeniden oluşturmanız gerekir.
- Tabloyu yeniden oluştururken foreign key'leri, index'leri, trigger'ları ve view'ları unutma. Bunlar veriyle birlikte otomatik olarak taşınmaz.
Sırada: Veriyi Eklemek
Bir bölüm boyunca tablolarla ve onları şekillendiren kısıtlamalarla uğraştın. Artık içlerini doldurma vakti — sonraki bölüm INSERT ile başlıyor; çoklu satır ekleme, varsayılan değerler ve SQLite'ın kısıtlamalarınla çakışan insert'lerde nasıl davrandığı da dahil.
Sıkça Sorulan Sorular
SQLite'ta bir tabloyu nasıl silerim?
DROP TABLE tablo_adi; komutunu kullanırsın. Tablo yoksa hata vermesin istiyorsan IF EXISTS ekle: DROP TABLE IF EXISTS users;. Bir tabloyu sildiğinde ona ait index'ler ve trigger'lar da silinir; foreign key kontrolü açıksa ve başka tablolar bu tabloya referans veriyorsa silme işlemi başarısız olur.
SQLite'ta ALTER TABLE neler yapabilir?
Toplam dört şey: RENAME TO (tabloyu yeniden adlandırma), RENAME COLUMN ... TO ... (sütunu yeniden adlandırma), ADD COLUMN (yeni sütun ekleme) ve DROP COLUMN (sütun silme — SQLite 3.35'ten itibaren). Hepsi bu kadar. Bir sütunun tipini değiştiremezsin, varsayılan değerini yerinde güncelleyemezsin, mevcut bir sütuna constraint ekleyemezsin.
SQLite'ta bir sütunun tipini veya constraint'lerini nasıl değiştiririm?
SQLite bunu doğrudan desteklemiyor. Standart çözüm tablo yeniden oluşturma yöntemidir: istediğin şemada yeni bir tablo oluştur, INSERT INTO new SELECT ... FROM old ile veriyi taşı, DROP TABLE old ile eskiyi sil ve ALTER TABLE new RENAME TO old ile yeni tabloyu eski isme getir. Atomik olması için tüm bu işlemleri bir transaction içine al.