Ayrıcalıklı bir çocukla bire çok ilişki kurmak nasıl?


22

Her ebeveyn için, çocukların bir veya sıfırının “favori” olarak işaretlendiği bir-çok ilişkiye sahip olmak istiyorum. Ancak, her ebeveynin bir çocuğu olmayacak. (Ebeveynleri bu sitedeki sorular, çocuklar cevaplar ve kabul edilen cevaplar olarak düşünün.) Örneğin,

TableA
    Id            INT PRIMARY KEY

TableB
    Id            INT PRIMARY KEY
    Parent        INT NOT NULL FOREIGN KEY REFERENCES TableA.Id

Gördüğüm gibi, aşağıdaki sütunu TableA'ya ekleyebilirim:

    FavoriteChild INT NULL FOREIGN KEY REFERENCES TableB.Id

veya aşağıdaki sütunu TabloB’e ekleyin:

    IsFavorite    BIT NOT NULL

İlk yaklaşımla ilgili sorun, normalize edilmiş bir şekilde olmayan boş bir yabancı anahtar getirmesidir. İkinci yaklaşımla ilgili sorun, en fazla bir çocuğun favori olmasını sağlamak için daha fazla çalışmanın yapılması gerektiğidir.

Hangi yaklaşımı kullanacağımı belirlemek için ne tür kriterler kullanmalıyım? Yoksa, düşünmediğim başka yaklaşımlar var mı?

SQL Server 2012 kullanıyorum.

Yanıtlar:


19

Diğer bir yol (boşlar olmadan ve FOREIGN KEYilişkilerde döngü olmadan ) "favori çocukları" saklamak için üçüncü bir tabloya sahip olmaktır. Çoğu DBMS'de, ek bir UNIQUEkısıtlamaya ihtiyacınız olacak TableB.

@Aaron, yukarıdaki adlandırma kuralının oldukça hantal olduğunu ve hatalara yol açabileceğini tanımlamak için daha hızlıydı. IdTablonun her yerinde sütunlarınız yoksa ve (birleştirilmiş olanların) görünen birçok tabloda aynı adlara sahipseniz, genellikle daha iyidir (ve aklı başında tutar) . Yani, burada bir yeniden adlandırma:

Parent
    ParentID        INT NOT NULL PRIMARY KEY

Child
    ChildID         INT NOT NULL PRIMARY KEY
    ParentID        INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
    UNIQUE (ParentID, ChildID)

FavoriteChild
    ParentID        INT NOT NULL PRIMARY KEY
    ChildID         INT NOT NULL 
    FOREIGN KEY (ParentID, ChildID) 
        REFERENCES Child (ParentID, ChildID)

SQL-Server'da (kullanmakta olduğunuz), IsFavoritebahsettiğiniz bit sütun seçeneğine de sahipsiniz . Her ebeveyn için benzersiz favori çocuk, filtrelenmiş bir Benzersiz Dizin aracılığıyla gerçekleştirilebilir:

Parent
    ParentID        INT NOT NULL PRIMARY KEY

Child
    ChildID         INT NOT NULL PRIMARY KEY
    ParentID        INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
    IsFavorite      BIT NOT NULL

CREATE UNIQUE INDEX is_FavoriteChild
  ON Child (ParentID)
  WHERE IsFavorite = 1 ;

Seçenek 1'in tavsiye edilmemesinin ana nedeni, en azından SQL Server'da değil, yabancı anahtar referanslarındaki dairesel yolların deseninin bazı problemleri olmasıdır.

Oldukça eski bir makaleyi okuyun: SQL By Design: The Dairesel Referans

İki tablodan satır eklerken veya silerken, "tavuk ve yumurta" sorunuyla karşılaşırsınız. Hangi tabloyu önce eklemeliyim - herhangi bir kısıtlamayı ihlal etmeden?

Bunu çözmek için, boşuna alınabilecek en az bir sütun tanımlamanız gerekir. (Tamam, teknik olarak, tüm sütun olabilir gerekmez olarak NOT NULLfakat sadece ertelenebilir kısıtlamaları uygulayan benzer bir soru Erwin'ın cevap @ görün Postgres ve Oracle gibi DBMS, içinde:. Sqlalchemy içinde Kompleks yabancı anahtar kısıtlaması nasıl Bu Postgres'te yapılabilir). Yine de, bu kurulum ince buzda kaymak gibi geliyor.

SO'da neredeyse aynı bir soruyu kontrol edin (ancak MySQL için) SQL'de, iki tablonun birbirine atıfta bulunması uygun mudur? Cevabım hemen hemen aynı. MySQL'in kısmi indeksleri yok, bu yüzden uygulanabilir tek seçenek nULL olabilecek FK ve ekstra masa çözümü.


9

Önceliğin ne olduğuna bağlı. İşten kaçmak mı istiyorsun yoksa en katı normalleşme kurallarına uymak mı istiyorsun?

Şahsen, IsFavoriteçocuk masasında olmanın daha iyi olduğunu düşünüyorum ve her ebeveyn için en fazla bir çocuğun o ebeveynin favorisi olduğundan emin olmak için çalışmaya hazırım. Öncelikli nedenin null yabancı anahtar meselesi ile ilgisi yok: Her iki yöne işaret eden tüm yabancı anahtarlardaki fikri sevmiyorum.

@ ypercube'un önerisi de iyi bir uzlaşmadır.

Bir kenara lütfen, lütfen, lütfen şemalarınızı anlamsız sütun isimleri ile karıştırmayın Id. IdAdını şema boyunca anlamlı bir şekilde görmeyi tercih ederim . Bir yazarı tanımlar mı? Tamam, ara onu AuthorID. Bir ürünü temsil ediyor mu? Tamam ProductID. Bu bir çalışan mı ve bazı durumlarda bir yönetici referansı veriyor mu? Tamam, EmployeeIDve ManagerIDdaha bana daha mantıklı IDve Parent. Bunu dışarıda bırakmak mantıklı gibi görünse de (ve içine koymaktan kaçınılmazsa da), karmaşık birleşimler yazmaya (ya da sorguları buraya yazmaya) başladığınızda, bu noktadaki bir demet birleşimi tersine çevirmeye çalışırken kesinlikle bir küfür hissedeceksiniz. gibi sütunlara a.Parent = b.ID... blecch.


1

Veriler çocuk tablosuna aittir. Bir ve sadece kaydın favori olarak işaretlenmesini (veya bizim tercih ettiğimiz adres olarak) işaretlenmesini sağlamak için masada bir tetikleyici ile doğru tutuyoruz.

Ancak, @ ypercube'un ayrı bir masa fikri de iyidir.

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.