CREATE TABLE Şema Tanımlamak İçin Kullanılır
SQLite'ta yapılandırılmış her veri parçası bir tabloda yaşar ve her tablo bir CREATE TABLE ifadesiyle başlar. Tabloya bir isim verir, sütunları sıralar ve isterseniz kısıtlar eklersiniz. SQLite şemayı veritabanı dosyasına yazar ve tablo kullanıma hazır hale gelir.
İşte sqlite tablo oluşturmanın en sade hali:
Üç kolon, bir birincil anahtar, bir tane de NOT NULL kuralı. id integer primary key olduğu için SQLite onu otomatik doldurdu; ikinci satırda da email için bir şey belirtilmediğinden NULL kalmasına izin verdi. İskelet bu kadar — tablo adı, kolonlar ve kısıtlar. Bu sayfadaki geri kalan her şey bu yapının farklı varyasyonlarından ibaret.
Söz Diziminin Parça Parça İncelenmesi
Bir kolon tanımı şu biçimdedir: ad TIP kısıt kısıt .... Klasik SQLite'ta tip belirtmek zorunlu değildir (bu konunun ayrıntısı type affinity sayfasında), ama yine de her zaman bir tip yazmak iyi bir alışkanlıktır — hem kodu okuyanlar hem de araçlar buna göre davranır.
Birkaç önemli not:
- Kısıtlamalar boşlukla peş peşe yazılır:
skuüzerindekiNOT NULL UNIQUEifadesi her iki kuralın da uygulandığı anlamına gelir. in_stocksütunundakiDEFAULT 1,INSERTsırasında o sütunun atlanmasına izin verir.- SQLite'ta boolean değerler için
INTEGERkullanılır — yerleşik birBOOLEANtipi yoktur.0false,1true demektir. - Son sütundan sonra virgül bırakırsanız sözdizimi hatası alırsınız. SQL bu konuda JavaScript'ten daha katıdır.
IF NOT EXISTS: Tekrar çalıştırmalarda hata almayın
Zaten o tabloyu içeren bir veritabanında CREATE TABLE çalıştırırsanız, SQLite hata fırlatır:
Hata: users tablosu zaten mevcut
İlk seferinde sorun değil ama yüzüncü seferde sinir bozucu bir hale geliyor. IF NOT EXISTS kullandığında, tablo zaten varsa komut hiçbir şey yapmadan geçiyor:
İkinci CREATE TABLE aslında hiçbir şey yapmaz — ne hata fırlatır ne de şemada bir değişiklik yapar. Açılış kodunda, migration script'lerinde ve aynı SQL'in birden fazla kez çalışabileceği her yerde tam olarak istediğiniz biçim budur.
Ama dikkat: IF NOT EXISTS sadece ismi kontrol eder. O isimde bir tablo varsa ama kolonları farklıysa, SQLite ona dokunmaz. Şemayı senin için "düzeltmez" ya da "güncellemez". Bu iş migration'ların işidir.
Kısıtlar: Şemayla Birlikte Gezen Kurallar
Kısıtlar (constraints), doğrulama mantığını doğrudan veritabanının içine taşımanın yoludur. Sürekli başvuracağın dört tanesi şunlar:
PRIMARY KEY— bir satırı benzersiz şekilde tanımlar. Detaylar için primary key dokümanına göz atabilirsiniz.NOT NULL— sütunun mutlaka bir değeri olması gerekir.DEFAULT değer—INSERTsırasında sütun belirtilmediğinde devreye girer. Sabit bir değer olabileceği gibidatetime('now')gibi bir ifade de olabilir.CHECK (expr)— her satır için sonucu doğru olmak zorunda.UNIQUE (col, col)— sütunların kombinasyonu üzerinden benzersizliği zorlayan tablo seviyesinde bir kısıttır.
Kısıtlar her INSERT ve UPDATE işleminde çalışır. Kuralı çiğneyen satır reddedilir ve sorgu hata verir. Hatalı verinin uygulamanın her köşesine yayılmadan veritabanı seviyesinde yakalanması, çok daha düşük maliyetlidir.
Foreign Key Oluşturma
Foreign key kısaca şunu söyler: "bu sütun, başka bir tablodaki bir satıra işaret ediyor." Verinin tutarlı kalmasını sağlar — var olmayan bir kullanıcıya referans veremezsin ve (uygun seçeneklerle) bir kullanıcıyı sildiğinde siparişlerinin de cascade ile silinmesini sağlayabilirsiniz.
SQLite'da kafa karıştıran ama mutlaka aklınızda tutmanız gereken bir nokta var: foreign key kontrolü varsayılan olarak kapalıdır. Kısıtların gerçekten denetlenmesini istiyorsanız, her bağlantı için PRAGMA foreign_keys = ON çalıştırmanız gerekir. Çoğu uygulama sürücüsü bunu sizin yerinize halleder ya da bir ayar olarak sunar; sizinki yapmıyorsa bağlantıyı açar açmaz bu pragma'yı çalıştırın.
Buradaki ON DELETE CASCADE, bir kullanıcı silindiğinde o kullanıcıya ait gönderilerin de otomatik olarak silineceği anlamına gelir. Diğer seçenekler SET NULL, RESTRICT ve varsayılan olan NO ACTION'dır; sonuncusu, alt kayıtlar varsa silme işlemini reddeder.
CREATE TABLE AS SELECT ile tablo oluşturma
Bazen bir sorgunun sonucunu hızlıca yeni bir tabloya kopyalamak istersiniz — anlık görüntü almak, yedek tutmak veya analiz sırasında geçici bir çalışma tablosu oluşturmak için. İşte CREATE TABLE ... AS SELECT tam da bunu yapar:
Yeni tablo; kolon adlarını, tiplerini (elinizden geldiğince) ve veriyi kopyalar. Asıl önemli olansa kopyalanmayanlar: birincil anahtar, NOT NULL kısıtı, indeksler ve yabancı anahtarlar gelmez. Yani elinizde sadece düz bir anlık görüntü olur. Bunu gerçek bir şemayı klonlamanın yolu olarak değil, hızlı denemeler için bir başlangıç noktası olarak düşünün.
Veriyi değil de yalnızca yapıyı almak istiyorsanız, sona WHERE 0 ekleyin:
Aynı sütun yapısına sahip boş bir tablo elde edersiniz; bunu sonradan dolduracağınız arşiv tabloları için oldukça pratiktir.
Geçici Tablolar (TEMP Table)
TEMP tablo, yalnızca aktif veritabanı bağlantısı süresince yaşar. Bağlantıyı kapattığınızda tablo da yok olur; ne temizlik yapmanız gerekir, ne de geride bir şema kalır:
Faydalı senaryolar: çok adımlı bir sorgu için satırları geçici olarak biriktirmek, CTE ile ifade edilemeyecek kadar dağınık ara sonuçları tutmak, uzun süren bir oturumda bağlantıya özel veriyi izole etmek. CREATE TEMP TABLE ile CREATE TEMPORARY TABLE aynı anlama gelir.
Bunu AS SELECT ile birleştirebilirsiniz: CREATE TEMP TABLE snapshot AS SELECT ... kalıbı, analiz sırasında bir sonuç kümesini "dondurmak" için sıkça kullanılır.
İsimleri Tırnak İçine Almak
Çoğu zaman sütun ve tablo adları çıplak tanımlayıcı olarak yazılır. Ama ayrılmış bir kelimeyi ya da içinde boşluk geçen bir adı kullanmak zorunda kalırsanız, bunu çift tırnak (SQL standardı) ya da ters tırnak (MySQL'den gelen, SQLite'ın da desteklediği bir alışkanlık) içine alın:
Çalışır çalışmasına ama tabloya her atıfta bulunduğunuzda ekstra bir yük getirir. orders, selection, user_id gibi sade isimleri tercih edin ve tırnak işini tamamen bırakın.
Gerçekçi bir örnek
Şimdiye kadar gördüklerimizi bir araya getirelim — küçük bir görev (tasks) uygulaması için sade bir şema. IF NOT EXISTS sayesinde her uygulama açılışında sorunsuz çalışır:
İşte canlıya alabileceğin bir şema: idempotent oluşturma, foreign key'ler aktif, done alanını dürüst tutan bir CHECK, makul varsayılan değerler ve kendi kendine dolan zaman damgaları.
Sırada: Veri Tipleri
CREATE TABLE ile INTEGER, TEXT, REAL yazabilirsiniz — ama SQLite bu değerleri nasıl saklayacağı konusunda meşhur şekilde esnek davranır. Bir sonraki sayfada SQLite'ın gerçekten kullandığı beş depolama sınıfını ve yazdığınız tipin neden her zaman elde ettiğiniz tip olmadığını ele alacağız.
Sıkça Sorulan Sorular
SQLite'ta tablo nasıl oluşturulur?
Temel sözdizimi şöyle: CREATE TABLE isim (kolon1 TIP, kolon2 TIP, ...). Her kolona bir isim, isteğe bağlı bir tip ve dilerseniz PRIMARY KEY, NOT NULL, DEFAULT gibi kısıtlar verebilirsiniz. Komut çalıştığı anda tablo oluşur ve veritabanı dosyasında kalıcı olarak yer alır.
CREATE TABLE içindeki IF NOT EXISTS ne işe yarar?
CREATE TABLE IF NOT EXISTS isim (...) ifadesi, tablo zaten varsa hiçbir şey yapmaz; sadece yoksa oluşturur. Bu kontrol olmadan aynı script'i mevcut bir veritabanında ikinci kez çalıştırdığınızda table already exists hatası alırsınız. Migration script'lerinde ve uygulama açılış kodlarında neredeyse standart bir koruma kalıbıdır.
SQLite'ta SELECT sonucundan tablo oluşturulabilir mi?
Evet, CREATE TABLE yeni_isim AS SELECT ... ile bir sorgunun sonucundan yeni bir tablo üretebilirsiniz. Ancak dikkat: bu yöntem sadece kolon isimlerini ve veriyi kopyalar; kaynak tablodaki primary key, foreign key, indeks veya diğer kısıtlar yeni tabloya taşınmaz. Snapshot almak ya da geçici çalışma tabloları için iyidir; gerçek bir şema yerine geçmez.
Geçici tablo (TEMP TABLE) ile normal tablo arasında ne fark var?
CREATE TEMP TABLE (veya CREATE TEMPORARY TABLE) ile oluşturulan tablo yalnızca o anki veritabanı bağlantısı için yaşar; bağlantı kapandığında otomatik silinir. Normal tablolar ise veritabanı dosyasında kalıcıdır. Geçici tablolar, ana şemayı kirletmeden ara sorgu sonuçlarını tutmak veya karmaşık hesaplamaları parçalamak için çok kullanışlıdır.