Yabancı Anahtar içeren tablo sütunları NULL olabilir mi?


235

Diğer tablolara birkaç kimlik sütunları olan bir tablo var.

Yabancı bir anahtarın yalnızca bütünlüğü zorlamasını istiyorum oraya veri koyarsam . Bu sütunu doldurmak için daha sonra bir güncelleme yaparsam, kısıtlamayı da kontrol etmelidir.

(Bu muhtemelen veritabanı sunucusuna bağlıdır, MySQL ve InnoDB tablo türünü kullanıyorum)

Bunun makul bir beklenti olduğuna inanıyorum, ama yanılıyorsam beni düzeltin.


6
MySQL hakkında bilmiyorum, ancak MS SQL Server yabancı anahtarlar istediğiniz semantik ile nulllable olmasını sağlar. Bunun standart davranış olduğunu düşünüyorum.
Jeffrey L Whitledge

1
yabancı anahtar, mySQL'de varsayılan olarak null olamaz, nedeni basittir, bir şeye başvurursanız ve null değerine izin verirseniz, veri bütünlüğünü kaybedersiniz. tablo kümesini oluşturduğunuzda null değerine izin ver ve sonra yabancı anahtar kısıtlamasını uygula. Güncellemede null değerini ayarlayamazsınız, size bir hata göndermelidir, ancak bu sütunu güncelleyemez ve yalnızca değiştirmeniz gereken alanları güncelleyebilirsiniz (yapmanız gerekir).
JoelBonetR

Yanıtlar:


245

Evet, kısıtlamayı yalnızca değer NULL olmadığında uygulayabilirsiniz. Bu, aşağıdaki örnekle kolayca test edilebilir:

CREATE DATABASE t;
USE t;

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT NULL, 
                    parent_id INT NULL,
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
) ENGINE=INNODB;


INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)


INSERT INTO child (id, parent_id) VALUES (2, 1);

-- ERROR 1452 (23000): Cannot add or update a child row: a foreign key 
-- constraint fails (`t/child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY
-- (`parent_id`) REFERENCES `parent` (`id`))

İlk ekleme geçer çünkü biz bir NULL ekleriz parent_id. parentTabloda bulunmayan bir değer eklemeye çalıştığımız için, ikinci ekleme yabancı anahtar kısıtlaması nedeniyle başarısız oluyor .


16
Üst tablo, INT NOT NULL kimliğiyle de bildirilebilir.
Will

@CJDennis Yalnızca bir satırın boş kimliğe sahip olmasını sağlarsanız, diğer satırlar için yedek değerler olarak kullanılabilir. (Yalnızca daha fazla sütun kullanırsanız DB için daha iyi çalışmasına rağmen.) Daha sonra bir değerin başlangıçta "varsayılan" (null kullanarak) veya bir "varsayılan" ile aynı olan değer. Boş kimliğe sahip bir satıra sahip olarak, bu satırın normal bir satır olarak kullanılmayacağını açıkça belirtebilir ve satırı diğer satırlar için bir tür dinamik varsayılan değer sağlamanın bir yolu olarak kullanabilirsiniz.
Ouroborus

1
Bence parent_id INT NULLbölüm (verbosely) eşittirparent_id int default null

Java kullanıcıları için yan not, ibatis veya diğer ORM kullanırsanız ve sınıf üyeleriniz intyerine ilkel kullanıcı kullanırsanız Integer, varsayılan asla boş olmaz, ancak 0 olur ve kısıtlamayı geçemezsiniz.
Jim Ford

32

Eklerken, boş sütun değerlerinin özellikle NULL olarak bildirilmesi gerektiğini, aksi takdirde (boş bir dizenin aksine) bir kısıtlama ihlali hatası alacağını buldum.


8
Buna izin vermek için sütunda varsayılan bir NULL değeri ayarlayamadınız mı?
Kevin Coulombe

Evet, çoğu dilde NULL boş bir dizgiden farklıdır. Başlarken belki ince, ama hatırlanması kritik.
Gary

Hey Backslider, "(boş bir dizenin tersine)" diyorsunuz, ama boş bir dize değeri ekleyeceğinizi kastettiğinizi değil, bunun yerine Değer için bir değer belirtmediğinizi sanmıyorum herşey? yani sütununuzda bahsetmediniz INSERT INTO {table} {list_of_columns}mi? Çünkü bu benim için doğrudur; sütundan bahsedilmemesi hataya neden olur, ancak NULL değerinin eklenmesi ve açıkça ayarlanması hatayı düzeltir. Doğruysam, bence @ Gary'nin yorumu geçerli değil (çünkü boş bir dize demek istemedin), ama @Kevin Coulombe yardımcı olabilir ...
Kızıl Bezelye

Evet, KevinCoulombe önerisi eserleri @, ben Entity Framework Core Göç komut ile bunu başarmak için nasıl tarif burada
Kırmızı Pea

NULL yabancı anahtarlar içeren bir kaydı güncellerken açık olma gerekçesinin yalnızca dize türleri (varchar, vb.) İçin geçerli olduğunu belirtmek önemlidir, aksi takdirde boş bir dize varsayılan olarak iletilebilir. Bu MySQL için geçerlidir ve güncelleme sırasında bir bütünlük hatası ile sonuçlanır.
CodeMantle

4

Evet, beklediğiniz gibi çalışır. Ne yazık ki, bunun MySQL kılavuzunda bunun açık bir ifadesini bulmakta sorun yaşıyorum .

Yabancı anahtarlar, değerin diğer tabloda bulunması gerektiği anlamına gelir. NULL , değerin yokluğunu ifade eder, bu nedenle bir sütunu NULL olarak ayarladığınızda, bu konuda kısıtlamaları zorlamaya çalışmak mantıklı olmaz.


Tasarım gereği Yabancı Anahtar null olmayan bazı anahtarlara (Birincil) başvurmalıdır, ancak geliştirme aşamasında ilk olarak alt tabloya eklenmiş birden fazla veriye ihtiyaç duyduğumuzda, kime başvuracağını bilmiyoruz (üst tablo) . Bu yüzden NULL değerine izin verdik. Üretimde NULL olması kabaca söylenebilecek bir tasarım akışı olacaktır.
vimal krishna

2

Yukarıdaki işler ancak bu işe yaramıyor. AÇIK SİLME KASKINI not edin

CREATE DATABASE t;
USE t;

CREATE TABLE parent (id INT NOT NULL,
                 PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT NULL, 
                parent_id INT NULL,
                FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE

) ENGINE=INNODB;


INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)

4
'Yukarıdakiler' ile ne demek istiyorsun? Başka bir cevaba atıfta bulunursanız, siparişin değişebileceğini unutmayın.
d219

2

Evet, değer NULL olabilir, ancak açık olmalısınız. Aynı durumu daha önce de yaşadım ve bunun neden olduğunu unutmak kolaydır ve bu yüzden ne yapılması gerektiğini hatırlamak biraz zaman alır.

Gönderilen veriler boş bir dize olarak yayınlanır veya yorumlanırsa başarısız olur. Ancak, INSERTING veya UPDATING sırasında değeri açıkça NULL olarak ayarlayarak, devam edebilirsiniz.

Ama bu programlamanın eğlencesi, değil mi? Kendi problemlerimizi yaratıp sonra çözüyoruz! Şerefe!


1

Bunun bir başka yolu, diğer tabloya bir VARSAYILAN öğe eklemek olacaktır. Örneğin, diğer tabloda uuid = 00000000-0000-0000-0000-000000000000'e yapılan herhangi bir işlem, herhangi bir işlem olmadığını gösterir. Ayrıca, kod mantığınızı etkilememek için bu kimliğin tüm değerlerini "nötr", örneğin 0, boş dize, boş olarak ayarlamanız gerekir.


2
Bu aynı şey değil. Varsayılan veya "nötr" bir değer, bir değerin yokluğu NULL ile aynı değildir. Varsayılan değerin değerini bir NULL üzerinde tartışmadan, ifadeniz bir litte karışıktır. "Bunun etrafındaki başka bir yol, diğer tabloya boş bir öğe eklemek olacaktır" gibi bir şey daha söylemelidir "Bunun etrafındaki başka bir yol, diğer tabloya bir VARSAYILAN öğe eklemek olacaktır"
blindguy

0

Ben de bu konuda takıldım. Ama sadece yabancı anahtarı tanımlayarak çözdüm unsigned integer. Aşağıdaki örneği bulun

CREATE TABLE parent (
   id int(10) UNSIGNED NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (
    id int(10) UNSIGNED NOT NULL,
    parent_id int(10) UNSIGNED DEFAULT NULL,
    FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.