it-swarm.dev

SQL: boş dize ve NULL değeri

Bu konunun biraz tartışmalı olduğunu ve internette yüzen birçok makale/görüş olduğunu biliyorum. Ne yazık ki, çoğu kişi NULL ve boş dize arasındaki farkın ne olduğunu bilmediğini varsayar. Bu yüzden birleştirmeler/toplamalar ile şaşırtıcı sonuçlar hakkında hikayeler anlatıyorlar ve genellikle biraz daha gelişmiş SQL dersleri yapıyorlar. Bunu yaparak, tüm noktayı kesinlikle kaçırırlar ve bu nedenle benim için işe yaramazlar. Umarım bu soru ve tüm cevaplar konuyu biraz ileriye taşır.

Diyelim ki sütunlardan birinin varchar türünde bir e-posta adresi olduğu kişisel bilgiler içeren bir tablom var (isim, doğum vb.). Bazı nedenlerden dolayı bazı kişilerin e-posta adresi vermek istemeyebileceğini varsayıyoruz. Bu tür verileri tabloya eklerken (e-posta olmadan), kullanılabilir iki seçenek vardır: hücreyi NULL olarak ayarlayın veya boş dizeye ('') ayarlayın. Bir çözümün diğerine göre seçilmesinin tüm teknik etkilerinin farkında olduğumu ve her iki senaryo için de doğru SQL sorguları oluşturabildiğimi varsayalım. Sorun, her iki değer teknik düzeyde farklı olsa bile, mantıksal düzeyde tamamen aynıdır. NULL'a baktıktan sonra '' Tek bir sonuca vardım: Adamın e-posta adresini bilmiyorum. Ayrıca ne kadar zor denesem de, NULL veya boş dize kullanarak bir e-posta gönderemedim, bu yüzden görünüşe göre çoğu SMTP sunucusu benim mantığımla aynı fikirde. Yani ben değeri bilmiyorum ve boş dize kötü bir şey düşünün NULL kullanmaya eğilimindedir.

Meslektaşları ile yapılan yoğun tartışmalardan sonra iki soru ile geldim:

  1. bilinmeyen bir değer için boş dize kullanarak bir veritabanı gerçekler hakkında "yalan" neden olduğunu varsayarak doğru muyum? Daha kesin olmak gerekirse: SQL'in değer nedir ve ne olmadığı fikrini kullanarak, sonuca varabilirim: e-posta adresimiz var, sadece boş olmadığını öğrenerek. Ama daha sonra, e-posta göndermeye çalışırken çelişkili bir sonuca varacağım: hayır, e-posta adresimiz yok, @! # $ Veritabanı yalan söylüyor olmalı!

  2. Boş bir dizenin '' başka bir şekilde (ek sütun gibi) saklamak zahmetli/verimsiz olan önemli bilgilerin (değer dışında ve değersiz) iyi bir taşıyıcı olabileceği herhangi bir mantıksal senaryo var mı? Bazen gerçek değerleri ve NULL'larla birlikte boş dize kullanmanın iyi olduğunu iddia eden birçok yazı gördüm, ancak şu ana kadar mantıklı olacak bir senaryo görmedim (SQL/DB tasarımı açısından).

Not; Bazı insanlar sadece kişisel bir zevk meselesi olduğunu cevaplamaya cazip gelecektir. Kabul etmiyorum. Benim için önemli sonuçları olan bir tasarım kararı. Bu yüzden bu konuda opionun mantıklı ve/veya teknik nedenlerle desteklendiği cevapları görmek istiyorum.

73
Jacek Prucia

NULL "e-posta adresi yok" için doğru seçim olduğunu söyleyebilirim. çok sayıda "geçersiz" e-posta adresi var ve "" (boş dize) yalnızca bir tane. Örneğin "foo" geçerli bir e-posta adresi değil, "a @ b @ c" geçerli değil vb. Dolayısıyla, "" geçerli bir e-posta adresi olmadığından, bu adresi "e-posta adresi yok" değeri olarak kullanmak için bir neden yoktur.

"" Bu sütun için bir değerim yok "demenin doğru yolu olmadığını söylemekte haklısın. "" (is bir değer.

"" İfadesinin geçerli bir değer olabileceği, NULL öğesinden ayrı olduğu bir kişinin ikinci adı olabilir. Her birinin bir orta adı yoktur, bu nedenle "orta ad yok" ("" - boş dize) ve "Bu kişinin orta adı olup olmadığını bilmiyorum" (NULL ). Boş bir dizenin hala bir sütun için geçerli bir değer olduğu başka birçok örnek vardır.

84
Dean Harding

Yukarıdaki yorumları kabul ederken, bu argümanı birincil motivasyon olarak ekleyebilirim:

  1. Veritabanına bakan herhangi bir programcı için NULL olarak işaretlenmiş bir alanın İsteğe bağlı bir alan olduğu açıktır. (yani kayıt, bu sütun için veri gerektirmez)
  2. Bir alanı NULL DEĞİL olarak işaretlerseniz, herhangi bir programcı sezgisel olarak Zorunlu bir alan olduğunu varsaymalıdır.
  3. Boş değerlere izin veren bir alanda, programcılar boş dizeler yerine boş değer görmeyi beklemelidir.

Kendini Belgeleyen Sezgisel Kodlama uğruna, boş dizeler yerine NULL kullanın.

41
colinbashbash

Örneğinizde doğrudan web alanından değerse - boş dize kullanırım. Kullanıcı e-posta sağlamak istemediğini belirtebilirse veya silebilirse - NULL.

İşte aklınıza gelebilecek noktalar ile bağlantı: https://stackoverflow.com/questions/405909/null-vs-empty-when-dealing-with-user-input/405945#405945

--- düzenlendi (Thomas yorumuna cevap olarak) ---

Veritabanları, bunları kullanan uygulamalar olmadan yaşamaz. Uygulama düzgün kullanamıyorsa, NULL veya '' tanımlamasının değeri yoktur.

Kullanıcının sunucuya kalıcı istek gönderecek olan UZUN formu doldurup enter tuşuna bastığı bir örneği ele alalım. E-postasını girmenin ortasında olabilir. Muhtemelen e-posta alanında ne varsa saklamak istersiniz, böylece daha sonra bitirebilir. Ya sadece bir karakter girerse? Bir karakter girip silerse ne olur? E-posta gerekli olmadığında, bazen kullanıcılar onu silmek isterler: alanı temizlemenin en kolay yolu. Ayrıca, e-posta gerekmediğinde, göndermeden önce doğrulamanız gerekir.

Başka bir örnek: kullanıcı spamto @ [bigcompany] .com olarak e-posta sağlar - bu durumda, mevcut ve geçerli olsa bile (ve hatta mevcut olabilir) bile e-posta göndermeye gerek yoktur. Böyle bir tane göndermek ucuz olabilir, ancak günlük abonelikler için bu tür e-postaları olan 10 bin kullanıcı varsa, bu tür doğrulama çok zaman kazandırabilir.

6

Null kullanın.

Tablodaki alanı boş bırakılır hale getirirken, '' değerini depolamanın bir anlamı yoktur. Sorguları da daha belirgin hale getirir.

E-posta adresine sahip kullanıcıları bulmak istiyorsanız hangi SQL sorgusu daha açık ve okunaklı?

  1. SELECT * FROM Users WHERE email_address != ''

  2. SELECT * FROM Users WHERE email_address IS NOT NULL

  3. SELECT * FROM Users WHERE email_address != '' and email_address IS NOT NULL

2 olduğunu söyleyebilirim. Her ne kadar 3, kötü verilerin depolandığı durumlarda daha sağlamdır.

Formdaki e-posta adresinin isteğe bağlı olması durumunda, tabloya da yansıtılması gerekir. SQL'de, boş değerli bir alandır, yani bilinmemektedir.

Sadece kötü bir tasarım dışında bir tabloda boş bir dize saklamak makul bir iş değeri düşünemiyorum. Bu, 'NULL' veya 'BLANK' dize değerini saklamak ve geliştiricilerin varsayalım null veya boş bir dize. Bana göre bu kötü tasarım. NULL olduğunda neden sakla ??

Sadece NULL kullanın ve herkesi biraz daha mutlu edeceksiniz.

DAHA FAZLA BİLGİ:

SQL üç değerli mantık sistemi kullanır: Doğru, Yanlış ve Bilinmeyen.

Daha iyi ve daha ayrıntılı bir açıklama için, geliştiricilere şunları okumasını öneririm: SQL Sorguları - DOĞRU ve YANLIŞ ötesinde .

5
spong

Ne yazık ki Oracle, sıfır uzunluktaki VARCHAR dizesinin temsilini NULL'ın temsiliyle karıştırdı. Her ikisi de dahili olarak sıfır değerine sahip tek bir baytla temsil edilir. Bu tartışmayı daha da zorlaştırıyor.

NULL'u çevreleyen karışıklıkların çoğu üç değerli mantık etrafında toplanır. Aşağıdaki sözde kodu düşünün:

if ZIPCODE = NULL
    print "ZIPCODE is NULL"
else if ZIPCODE <> NULL
    print "ZIPCODE is not NULL"
else print "Something unknown has happened"

Üçüncü mesajı beklemezsiniz, ancak üç değerli mantık altında elde edeceğiniz şey budur. Üç değerli mantık insanları çok sayıda hataya yönlendirir.

Başka bir karışıklık kaynağı, gece havlamayan köpeklerden bir çıkarım yapmak gibi, veri yokluğundan çıkarımlar çizmektir. Çoğu zaman bu çıkarımlar, NULL yazarının düşünmeyi amaçladığı şey değildi.

Bunu söyledikten sonra, NULL'un veri eksikliğini iyi işlediği ve tam olarak istediğiniz sonuçları ürettiği birçok durum vardır. Bir örnek, isteğe bağlı ilişkilerdeki yabancı anahtarlardır. Belirli bir satırda hiçbir ilişki belirtmek için NULL kullanırsanız, bu satır beklediğiniz gibi bir iç birleştirmeden çıkar.

Ayrıca, saklanan verilerde (altıncı normal form) NULLS'den tamamen uzak dursanız bile, herhangi bir dış birleşim yaparsanız, yine de NULLS ile başa çıkmak zorunda kalacağınızı unutmayın.

5
Walter Mitty

Bence Dean Hardings'in cevabı bunu çok iyi kaplıyor. DB düzeyinde NULLs vs boş dizeleri hakkında konuşurken diğer veri türleri hakkında bir düşünmek gerektiğini belirtmek istiyorum dedi. Hiçbir tarih belirtilmediğinde minimum tarihi depolar mısınız? veya int sağlanmadığında -1? Değeriniz olmadığında bir değerin saklanması, o zaman bir dizi değerin tümünü izlemeniz gerektiği anlamına gelir. Her veri türü için en az bir tane (muhtemelen -1'in gerçek bir değer olduğu vakaları alırken daha fazla alternatifiniz olması gerekir). Eğer bir şey yapmak ama uygulama düzeyinde "şişman" bir şey yapmak istiyorsanız/onların veri kirletmeye gerek yoktur.

5
bendemes

belirli teknik soru için, sorun boş dizeye karşı null değil, doğrulama hatası. Boş bir dize geçerli bir e-posta adresi değil!

felsefi soru için cevap benzerdir: girdilerinizi doğrulayın. Boş bir dize, söz konusu alan için geçerli bir değerse, onu bekler ve kodlar; değilse, null kullanın.

Boş bir dize şu soruyu cevaplamak için geçerli bir giriş olacaktır: Mime zürafa ne dedi?

3
Steven A. Lowe

NULL ve boş dize olması için bir neden düşünebiliriz:

  • Geçerli bir e-posta adresiniz var: [email protected]
  • Hiçiniz yok (ve muhtemelen bir tane istemelisiniz): NULL
  • Bu kişinin bir e-posta adresi olmadığını biliyorsun: Empty String.

Ancak bunu tavsiye etmiyorum ve hiçbirinin mevcut olmadığını bilip bilmediğinizi sormak için ayrı bir alan kullanmam.

2
Marcel

Anladığım kadarıyla soru, NULL ve boş dizgenin hangi yorumlarının seçilmesi gerektiğidir. Bu, partiküler alanın kaç durumunun olabileceğine bağlıdır.

Yorum, veritabanına nasıl erişildiğine bağlıdır. Kodda, veritabanını tamamen soyutlayan bir katman varsa, çalışan herhangi bir ilke (iki coulmn dahil) seçmekten tamamen kabul edilebilir. (Politikayı açıkça belgelemek önemlidir). Ancak, veritabanına çeşitli yerlerde erişiliyorsa, kodun bakımı daha zor olacağı ve bu durumda hatalı olabileceğinden, çok basit bir şema kullanmalısınız.

1
apoorv020

Temel olarak mantıksal düzeyde "geçersiz" değer ile "kullanıcı girişi yok" arasında hiçbir fark yoktur, çoğu zaman sadece "özel durumlar" dır. Hata durumu.

Null değerine sahip olmak ek alan gerektirir: bayt/satır başına tavan (column_with_null/8).

Boş hücre ve null değeri bir şeyin yanlış olduğunu işaretlemenin iki yoludur/varsayılan değer olmalıdır. Neden 2 "yanlış" duruma ihtiyacınız var? Ek alan alır ve boş dizelerle tamamen aynı anlama geliyorlarsa, NULL'ları neden kullanıyorsunuz? Bu, tamamen aynı anlama gelen (yani) iki şeye sahip olduğunuzda karışıklık ve fazlalık getirecektir, boş dizeler yerine NULL'lar kullanmanız gerektiğini unutmak kolaydır (örneğin, kullanıcı bazı alanları ommitede).

Ve verileriniz karmaşaya dönüşebilir. Mükemmel bir dünyada "veriler her zaman doğru olacak ve hatırlayacağım" diyeceksiniz ... ama insanlar bir takımda çalışmak zorunda olduğunda ve herkes tam olarak sizin seviyenizde olmadığında NEREDE (aa. xx <> '' VE bb.zz IS NULL DEĞİL)

Yani ekip üyelerimi her geçen gün düzeltmek yerine basit bir kural uyguluyorum. Boş değer yok, ASLA!

NULL-NULL değerlerini saymak daha hızlıdır ... basit soru, bunun için ne yapmanız gerekir?

1
Slawek

DB perspektifinden değil, program perspektifinden görme eğilimim var. Bu sorunun SQL tıklaması için olduğunu biliyorum, ama gerçekten, kaç kullanıcı artık verilere doğrudan erişiyor?

Bir programda null/hiçbir şeyden hoşlanmıyorum. Birkaç istisna var ama bunlar sadece. Ve bu istisnalar gerçekten sadece kötü uygulamalardır.

Dolayısıyla, kullanıcı e-postayı koymadıysa, bunun geçerli olup olmadığını belirleyen bir şey olmalıdır. Boş bir e-posta yolundaysa boş bir dize görüntüler. Kullanıcı bir e-posta koymadıysa ve bu bir kuralı ihlal ediyorsa, nesne bunu belirtmelidir.

Null'a sahip olma fikri eski okuldur ve modern programcıların uğraşması gereken bir şeydir.

DB tasarımında bile, e-posta alanı null değerlere izin vermiyor ve sıfır uzunluklu bir dizeye sahip değil ve kullanıcının bir şey girip girmediğini gösteren başka bir alana sahip değil mi? Bir bit bir DBMS sormak o kadar mı? DB, bence, ne iş mantığını ne de görüntü mantığını ele almamalıdır. Bunun için inşa edilmedi ve bu yüzden çok zayıf bir iş yapıyor.

1
ElGringoGrande