วิธีการเชื่อมโยงสองแถวในตารางเดียวกัน


11

ฉันมีตารางที่แถวสามารถเชื่อมโยงซึ่งกันและกันและตามหลักเหตุผลความสัมพันธ์ไปทั้งสองทาง (โดยทั่วไปไม่มีทิศทาง) ระหว่างสองแถว (และหากคุณสงสัยว่าใช่นี่ควรเป็นหนึ่งตารางมันเป็นสองสิ่งที่มีเอนทิตี / ประเภทตรรกะที่เหมือนกัน) ฉันสามารถคิดถึงวิธีที่จะแสดงสิ่งนี้:

  1. เก็บความสัมพันธ์และสิ่งที่ตรงกันข้าม
  2. จัดเก็บความสัมพันธ์ทางเดียว จำกัด ฐานข้อมูลจากการจัดเก็บในทางอื่นและมีดัชนีสองรายการที่มีคำสั่งตรงกันข้ามสำหรับ FKs (ดัชนีหนึ่งรายการเป็นดัชนี PK)
  3. จัดเก็บความสัมพันธ์ทางเดียวด้วยดัชนีสองรายการและอนุญาตให้แทรกสองวิธีต่อไปได้
  4. สร้างตารางการจัดกลุ่มบางประเภทและมี FK ไว้ในตารางต้นฉบับ (เพิ่มคำถามจำนวนมากตารางการจัดกลุ่มจะมีตัวเลขเท่านั้นเพราะเหตุใดถึงมีตารางทำให้ FK NULLable หรือมีกลุ่มที่มีแถวเดียวเชื่อมโยงกัน)

อะไรคือข้อดีและข้อเสียที่สำคัญของวิธีการเหล่านี้และแน่นอนมีวิธีที่ฉันไม่เคยคิดบ้างไหม?

นี่เป็น SQLFiddle จะเล่นกับ: http://sqlfiddle.com/#!12/7ee1a/1/0 (เกิดขึ้นเป็น PostgreSQL เนื่องจากเป็นสิ่งที่ฉันใช้ แต่ฉันไม่คิดว่าคำถามนี้เฉพาะเจาะจงมากกับ PostgreSQL) ปัจจุบันมีการจัดเก็บทั้งความสัมพันธ์และย้อนกลับเป็นตัวอย่าง


ค่าที่กำหนดสามารถเกี่ยวข้องกับมากกว่าหนึ่งค่าได้หรือไม่? ค่าที่กำหนดเกี่ยวข้องกับค่าอื่นเสมอหรือไม่? พวกเขาแบ่งปันข้อมูลทั่วไปอื่น ๆ ที่เหมือนกันหรือไม่
ฟิลᵀᴹ

ใช่พวกเขาสามารถเกี่ยวข้องกับมากกว่า 1 แถวอื่น ๆ ไม่พวกเขาไม่จำเป็นต้องเกี่ยวข้องกับแถวอื่นเสมอไป พวกเขาไม่จำเป็นต้องมีข้อมูลทั่วไป ขอขอบคุณ.
jpmc26

อุ่ย ลืม @Phil แก้ไขด้วยเพื่อเพิ่มโครงสร้างที่มีศักยภาพที่เพิ่งเกิดขึ้นกับฉัน
jpmc26

คำตอบ:


9

สิ่งที่คุณออกแบบดี สิ่งที่ต้องเพิ่มเป็นข้อ จำกัด ในการทำให้ความสัมพันธ์ไม่มีทิศทาง ดังนั้นคุณไม่สามารถมี(1,5)แถวโดยไม่ต้องเพิ่ม(5,1)แถวได้เช่นกัน

สามารถทำได้*โดยมีข้อ จำกัด ในการอ้างอิงตนเองบนตารางบริดจ์

*: สามารถทำได้ใน Postgres, Oracle, DB2 และ DBMS ทั้งหมดที่ใช้ข้อ จำกัด กุญแจต่างประเทศตามมาตรฐาน SQL อธิบาย (รอการตัดบัญชีเช่นการตรวจสอบเมื่อสิ้นสุดการทำธุรกรรม) การตรวจสอบรอการตัดบัญชีนั้นไม่จำเป็นจริงๆเช่นเดียวกับ SQL- เซิร์ฟเวอร์ที่ตรวจสอบพวกเขาเมื่อสิ้นสุดคำสั่งและโครงสร้างนี้ยังใช้งานได้ คุณไม่สามารถทำเช่นนี้ใน MySQLเพราะ"การตรวจสอบ InnoDB ไม่ซ้ำกันและต่างประเทศ KEY จำกัด แถวโดยแถว"

ดังนั้นใน Postgres ต่อไปนี้จะตรงกับความต้องการของคุณ:

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)
);

ทดสอบที่: SQL-Fiddle

หากคุณพยายามเพิ่มแถว(1,5):

INSERT INTO bridge_x VALUES
(1,5) ;

มันล้มเหลวด้วย:

ข้อผิดพลาด: แทรกหรืออัปเดตบนตาราง "bridge_x" ละเมิดข้อ จำกัด กุญแจต่างประเทศ "x_x_directionless"
รายละเอียด: รหัส (x_id2, x_id1) = (5, 1) ไม่อยู่ในตาราง "bridge_x":
INSERT INTO bridge_x VALUES (1,5)

นอกจากนี้คุณสามารถเพิ่มCHECKข้อ จำกัด หากคุณต้องการห้าม(y,y)แถว:

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

มีวิธีอื่น ๆ ที่จะใช้สิ่งนี้ตามที่คุณพูดถึงเช่นการจัดเก็บเพียงทิศทางเดียวของความสัมพันธ์ (ในหนึ่งแถวไม่ใช่สอง) โดยการบังคับใช้รหัสที่ต่ำกว่าในx_id1และรหัสที่สูงขึ้นในx_id2คอลัมน์ ดูเหมือนว่าจะนำมาใช้ง่ายขึ้น แต่มักจะนำไปสู่การค้นหาที่ซับซ้อนมากขึ้นในภายหลัง:

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
);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.