Aynı tablodaki iki satırı ilişkilendirme


11

Satırların birbirleri ile ilişkili olabileceği bir tablo var ve mantıksal olarak, ilişki iki satır arasında her iki şekilde (temelde, yönsüz) gider. (Ve merak ediyorsanız, evet, bu gerçekten bir tablo olmalıdır. Aynı mantıksal varlık / türden iki şeydir.) Bunu temsil etmenin birkaç yolunu düşünebilirim:

  1. İlişkiyi ve tersini sakla
  2. İlişkiyi bir şekilde saklayın, veritabanını başka bir şekilde saklamaktan koruyun ve FK'ler için ters sırada iki dizine sahip olun (bir dizin PK dizini)
  3. İlişkiyi iki dizinle bir şekilde saklayın ve ikincinin yine de eklenmesine izin verin (sesler biraz yucky, ama hey, bütünlük)
  4. Bir çeşit gruplama tablosu oluşturun ve orijinal masasında bir FK'ye sahip olun. (Çok fazla soru soruyor. Gruplama tablosunda sadece bir sayı var; neden tablo bile var? FK NULLable yapın veya tek sıralı gruplar ilişkili mi?)

Bu yolların bazı büyük artıları ve eksileri nelerdir ve elbette, düşünmediğim bir yol var mı?

İşte oynamak için bir SQLFiddle: http://sqlfiddle.com/#!12/7ee1a/1/0 . (Ben kullandığım için PostgreSQL olduğu gibi, ama bu sorunun PostgreSQL için çok spesifik olduğunu düşünmüyorum.) Şu anda hem örnek hem de tersini saklıyor.


Belirli bir değer birden fazla birbiriyle ilişkili olabilir mi? Belirli bir değer her zaman başka bir değerle mi ilgili? Aynı diğer ortak verileri paylaşıyorlar mı?
Philᵀᴹ

Evet, 1'den fazla satırla ilişkilendirilebilirler. Hayır, her zaman başka bir satırla ilgili değildir. Ortak verilerinin olması gerekmez. Teşekkür ederim.
jpmc26

Hata. @Phil'i unuttum. Ayrıca, başıma yeni gelen potansiyel bir yapı eklemek için düzenlendi.
jpmc26

Yanıtlar:


9

Tasarladığınız iyi. Eklenmesi gereken, ilişkiyi yönlendirmek için bir kısıtlamadır. Dolayısıyla, bir (1,5)satır eklenmeden de bir satırınız olamaz (5,1).

Bu , köprü tablosunda kendinden referanslı bir kısıtlamayla * gerçekleştirilebilir .

*: SQL standardının tanımladığı gibi yabancı anahtar kısıtlamaları uygulayan Postgres, Oracle, DB2 ve tüm DBMS'de gerçekleştirilebilir (ertelenmiş, örneğin işlem sonunda kontrol edilir.) SQL'de olduğu gibi ertelenmiş kontrol gerçekten gerekli değildir. Açıklama sonunda onları kontrol sunucu ve bu inşaat hala çalışıyor. Sen MySQL bunu yapamaz çünkü "InnoDB'nin çekleri EŞSİZ ve yabancı anahtar kısıtlamaları satır-by-satır" .

Yani, Postgres'de aşağıdakiler gereksinimlerinize uygun olacaktır:

CREATE TABLE x
(
  x_id SERIAL NOT NULL PRIMARY KEY,
  data VARCHAR(10) NOT NULL
);

CREATE TABLE bridge_x
(
  x_id1 INTEGER NOT NULL REFERENCES x (x_id),
  x_id2 INTEGER NOT NULL REFERENCES x (x_id),
  PRIMARY KEY(x_id1, x_id2),
  CONSTRAINT x_x_directionless
    FOREIGN KEY (x_id2, x_id1)
    REFERENCES bridge_x (x_id1, x_id2)
);

Test yeri: SQL-Fiddle

Bir satır eklemeye çalışırsanız (1,5):

INSERT INTO bridge_x VALUES
(1,5) ;

Başarısız:

HATA: "bridge_x" tablosuna ekleme veya güncelleştirme yabancı anahtar kısıtlamasını "x_x_directionless" ihlal ediyor
Ayrıntı: Anahtar (x_id2, x_id1) = (5, 1) "bridge_x" tablosunda yok .:
INSERT INTO bridge_x VALUES (1,5)

Ayrıca, satırları CHECKyasaklamak istiyorsanız bir kısıtlama ekleyebilirsiniz (y,y):

ALTER TABLE bridge_x
  ADD CONSTRAINT x_x_self_referencing_items_not_allowed
    CHECK (x_id1 <> x_id2) ;

Bunu belirttiğiniz gibi uygulamanın başka yolları da vardır; örneğin x_id1, x_id2sütundaki alt kimliği ve yüksek kimliği zorlayarak ilişkinin yalnızca bir yönünü (iki satır değil, bir satırda) saklamak gibi . Uygulanması daha kolay görünüyor, ancak genellikle daha sonra daha karmaşık sorgulara yol açar:

CREATE TABLE bridge_x
(
  x_id1 INTEGER NOT NULL REFERENCES x (x_id),
  x_id2 INTEGER NOT NULL REFERENCES x (x_id),
  PRIMARY KEY(x_id1, x_id2),
  CONSTRAINT x_x_directionless
    CHECK (x_id1 <= x_id2)                       -- or "<" to forbid `(y,y)` rows
);
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.