Ekmeğini Hak Eden İki Kısıtlama
Şemadaki dağınıklıktan doğan hataların çoğu ya beklenmedik bir yerde NULL çıkmasından ya da uygulamanın varsayım yaptığı bir değerin sütunda hiç olmamasından kaynaklanır. İşte tam bu noktada NOT NULL ve DEFAULT devreye giriyor — üstelik eklemenin maliyeti neredeyse sıfır.
Bir sütun zorunlu ve geri dönüş değeri yok. Diğer ikisinin varsayılanı var. INSERT ifadesinin yalnızca email vermesi yetti; gerisini SQLite kendi doldurdu. Özelliğin tamamı tek örnekte bu kadar — sayfanın geri kalanı uç durumlarla ilgili.
NOT NULL: "NULL Kabul Edilmez, Tartışma Yok"
sqlite NOT NULL kısıtlaması adı üstünde olanı yapar. Sütuna NULL yazma denemesi — ister varsayılanı olmayan bir INSERT'te sütunu atlayarak, ister doğrudan NULL yazarak olsun — patlar:
Hata mesajı şu şekildedir:
Runtime error: NOT NULL constraint failed: posts.title
NULL değerini doğrudan geçtiğinizde de aynı sonucu alırsınız:
INSERT INTO posts (id, title) VALUES (1, NULL);
-- Çalışma zamanı hatası: NOT NULL constraint failed: posts.title
Bu, veritabanıyla yaptığınız anlaşma gibi düşün. Bir sütun mantıken zorunluysa NOT NULL olarak işaretle; böylece koca bir hata sınıfını baştan eler, uygulama kodu veritabanına gizlice NULL sokuşturamaz.
Çağıran taraf değer vermediğinde DEFAULT devreye girer
DEFAULT, yalnızca INSERT ifadesi o sütundan hiç bahsetmediğinde devreye girer. Açıkça yazılmış bir NULL'ı kurtarmaz:
İlk INSERT varsayılan değere yaslanıyor, ikincisi ise onu eziyor. Eğer INSERT INTO tasks (title, status) VALUES ('x', NULL) yazsaydınız, NOT NULL constraint failed hatasını yerdiniz — çünkü sütun açıkça belirtildiği anda varsayılan devreye girmiyor.
Akılda tutulması gereken model şu: DEFAULT, yazılmamış sütunların yerine geçer. NOT NULL ise null değerleri hangi yoldan gelirse gelsin reddeder. Bu ikisi birbirinden bağımsız özelliklerdir ve birlikte gayet uyumlu çalışır.
Varsayılan Değer Olarak İfade Kullanımı
Sabit bir değer atamak en yaygın durumdur (DEFAULT 0, DEFAULT '', DEFAULT 'pending'), ama SQLite parantez içinde bir ifade vermenize de izin verir. Satırlara oluşturulma zamanını basmak ya da rastgele bir ID üretmek tam olarak böyle yapılır:
Bilmeniz gereken birkaç nokta var:
- İfade her
INSERTişleminde yeniden değerlendirilir, tablo oluşturulurken bir kere değil. Yani her satır kendi timestamp'ini ve kendi token'ını alır. CURRENT_TIMESTAMP,CURRENT_DATEveCURRENT_TIMEparantez gerektirmeyen üç özel anahtar kelimedir. Bunların dışındaki her şey parantez ister.- İfade başka sütunlara veya alt sorgulara referans veremez; kendi kendine yetmesi gerekir.
Bir sütunun opsiyonel olmasını ama değer verildiğinde otomatik damgalanmasını istiyorsanız, NOT NULL'u kaldırıp default'u koruyun. Hem zorunlu hem de otomatik damgalı olsun istiyorsanız ikisini birden kullanın.
DEFAULT NULL Kullanımı Geçerlidir (ve Bazen Tam da İstenen Şey Budur)
DEFAULT NULL yazmak, hiç default tanımlamamakla aynı şeydir — değer vermediğinizde sütun NULL olur. Yine de şemada "değer yok" durumunun bilinçli bir başlangıç hali olduğunu açıkça belirtmek istediğinizde işe yarar:
bio ve avatar burada aynı şekilde davranır. bio üzerindeki DEFAULT NULL, kod biçiminde yazılmış bir yorum gibi düşünülebilir; şemayı okuyan birine, "bio'nun boş olması bir hata değil, normal bir durumdur" mesajını verir.
Mevcut bir tabloya NOT NULL eklemek
İşler burada biraz karışıyor. SQLite'ın ALTER TABLE komutu bilinçli olarak kısıtlı tutulmuştur — Postgres'teki gibi ALTER COLUMN ... SET NOT NULL çalıştıramazsınız. Yapabilecekleriniz, sütunun zaten var olup olmamasına göre değişir.
Yepyeni bir sütun için ADD COLUMN ... NOT NULL çalışır, ancak mutlaka bir varsayılan değer vermeniz gerekir — aksi halde mevcut satırlar bir anda NOT NULL sütununda NULL taşımak zorunda kalır ki bu mümkün değildir:
Aynı işlemi DEFAULT olmadan denerseniz hata alırsınız:
ALTER TABLE products ADD COLUMN sku TEXT NOT NULL;
-- Çalışma zamanı hatası: Varsayılan değeri NULL olan bir NOT NULL sütunu eklenemez
Mevcut bir sütunu yerinde değiştirmek mümkün değil. Standart yöntem şu klasik "yeniden inşa" dansı: istediğiniz kısıtlamayla yeni bir tablo oluştur, veriyi taşı, eskisini sil, yenisini yeniden adlandır. Bunun detaylarını drop-and-alter-table sayfasında ele alacağız — şimdilik bu kısıtlamanın gerçek olduğunu bilmeniz ve şemanı buna göre tasarlamanız yeterli.
Gerçek Hayattan Bir Kombinasyon
Üretim ortamındaki tabloların çoğunda bu iki kısıtlama, "uygulamanın doğru kabul ettiği şeyleri" şemaya yansıtmak için birlikte kullanılır:
Şemaya yukarıdan aşağıya bir göz at; tek satır kod görmeden uygulamanın ne yaptığını çıkarabilirsiniz. customer zorunlu ve yedeği yok — siparişin kime ait olduğunu çağıran taraf bilmek zorunda. Para, para birimi ve durum alanlarının hepsinde mantıklı varsayılanlar var; bu sayede en sade INSERT bile tutarlı bir satır üretiyor. notes opsiyonel. created_at ise veritabanı tarafından dolduruluyor — ki zaten doldurulması gereken tek yer orası.
Bu kısıtlamaların asıl değeri burada: varsayımları, veritabanının kendisinin dayattığı kurallara dönüştürüyorsunuz.
Sık Yapılan Hatalar
İnsanları en çok ısıran birkaç nokta:
- Açıkça
NULLyazmakDEFAULT'u devre dışı bırakır.INSERT INTO t (col) VALUES (NULL)varsayılan değeri kullanmaz. Varsayılanın devreye girmesi için sütunun, sütun listesinde hiç bulunmaması gerekir. - İfade içeren varsayılanlar parantez ister.
DEFAULT CURRENT_TIMESTAMPçalışır (zaten üç özel anahtar kelimeden biri). AmaDEFAULT lower(hex(randomblob(8)))çalışmaz — parantez içine al:DEFAULT (lower(hex(randomblob(8)))). NOT NULLile boş string aynı şey değildir.''geçerli birTEXTdeğeridir ve kısıtlamayı tetiklemez. Boş stringi de yasaklamak istiyorsanız, bu artıkCHECKkısıtlamasının işi (sonraki sayfa).ADD COLUMN ... NOT NULLiçinNULLolmayan birDEFAULTşarttır. Varsayılan vermezsen SQLite işlemi reddeder.
Sırada: CHECK Kısıtlamaları
NOT NULL ve DEFAULT ikilisi "var olmak zorunda" ve "yoksa şunla doldur" senaryolarını kapsıyor. Bir sonraki doğrulama katmanı için — "pozitif olmalı", "şu değerlerden biri olmalı", "bitiş tarihi başlangıçtan sonra olmalı" gibi — SQLite sana CHECK kısıtlamalarını sunuyor. Bunlar, her satırın sağlaması gereken keyfi boolean ifadeler yazmana izin verir. Onu da bir sonraki sayfada anlatacağız.
Sıkça Sorulan Sorular
SQLite'ta bir sütunu nasıl zorunlu yaparım?
Sütun tanımına NOT NULL eklemeniz yeterli: email TEXT NOT NULL. O sütunu NULL bırakmaya çalışan her INSERT veya UPDATE, NOT NULL constraint failed hatasıyla başarısız olur. Çağıran taraf değer vermediğinde devreye girecek bir yedek değer istiyorsanız bunu bir DEFAULT ile birlikte kullanın.
SQLite'ta varsayılan değerler nasıl çalışır?
DEFAULT <değer>, bir INSERT o sütun için değer belirtmediğinde kullanılacak değeri tanımlar. Varsayılan; bir sabit (DEFAULT 0, DEFAULT 'pending'), NULL ya da parantez içinde bir ifade olabilir: DEFAULT (CURRENT_TIMESTAMP) veya DEFAULT (lower(hex(randomblob(8)))) gibi. İfade tipindeki varsayılanlar her eklemede yeniden hesaplanır.
SQLite neden insert sırasında 'NOT NULL constraint failed' diyor?
NOT NULL olan ve DEFAULT tanımı bulunmayan bir sütuna değer vermeden satır eklemeye çalışıyorsunuz. Çözüm: o sütunu INSERT ifadesine dahil edin, sütuna bir DEFAULT tanımlayın ya da kısıtlamayı kaldırın. Açıkça NULL geçmek de aynı hatayı tetikler — NOT NULL, değerin nereden geldiğine bakmaksızın null'ları reddeder.
SQLite'ta var olan bir sütuna NOT NULL eklenebilir mi?
Doğrudan eklenemez; SQLite'ta ALTER TABLE ... ALTER COLUMN diye bir şey yok. İki yolunuz var: ya NOT NULL DEFAULT <değer> ile yeni bir sütun eklersiniz (mevcut satırlar için DEFAULT zorunludur) ya da tabloyu yeniden inşa edersiniz: kısıtlamayı içeren yeni bir tablo oluşturup veriyi kopyalar, eskisini düşürüp yenisini yeniden adlandırırsınız.