วิธีการใช้ความสัมพันธ์แบบหนึ่งต่อหนึ่งแบบตัวต่อตัวและแบบกลุ่มต่อกลุ่มในขณะที่ออกแบบตาราง


281

ใครสามารถอธิบายวิธีการใช้ความสัมพันธ์แบบหนึ่งต่อหนึ่งแบบตัวต่อตัวและแบบกลุ่มต่อกลุ่มในขณะที่ออกแบบตารางพร้อมตัวอย่าง


การปรับใช้มีแนวโน้มที่จะแตกต่างกันไปตาม RDBMS เป้าหมายดังนั้นผู้ขายใดที่คุณกำหนดเป้าหมาย
billinkc

1
นั่นไม่ใช่คำถามทำการบ้าน ... !! ฉันกำลังเตรียมตัวสำหรับการสัมภาษณ์ .. ดังนั้นคิดว่าจะถามที่นี่ ... ฉันลอง googling แต่ havne ไม่พบบทความที่ดีที่ฉันได้อธิบายสิ่งเหล่านี้ทั้งหมดในที่เดียว ... !!
คลังแสง

ฉันกำลังกำหนดเป้าหมายฐานข้อมูล oracle .. !!
คลังแสง

คุณอาจต้องการที่จะอ่านโพสต์นี้เช่นกัน .... stevencalise.wordpress.com/2010/09/01/... ฉันจะให้ความสนใจใกล้เคียงกับจุดที่ 2 และ 3
tsells

3
@tsells บางครั้งคุณถูกถามคำถามที่ไม่ได้ใช้กับสิ่งที่อยู่ในเรซูเม่ของคุณหรือโดยตรงกับความต้องการของงาน ฉันได้รับรายชื่อคนที่สัมภาษณ์ฉันที่ บริษัท แห่งหนึ่งและอีกคนหนึ่งเป็นผู้เชี่ยวชาญ DB ฉันไม่มี SQL ในประวัติการทำงานของฉัน แต่ฉันได้ค้นหาแบบสอบถาม SQL แบบง่าย ๆ สองสามข้อ มันช่วยและฉันได้งานฉันพบในภายหลังผู้จัดการการจ้างงานกังวลว่าผู้สมัครตอบอย่างไรภายใต้ความกดดัน พวกเขายอมรับขีด จำกัด ของพวกเขาหรือปลอมทางผ่าน? หากพวกเขายอมรับข้อ จำกัด ของพวกเขาพวกเขาพยายามอยู่แล้วหรือให้ขึ้นเร็วเกินไป?
Doug Cuthbertson

คำตอบ:


478

หนึ่งต่อหนึ่ง:ใช้ foreign key ไปยังตารางอ้างอิง:

student: student_id, first_name, last_name, address_id
address: address_id, address, city, zipcode, student_id # you can have a
                                                        # "link back" if you need

คุณต้องใส่ข้อ จำกัด ที่ไม่ซ้ำกันในคอลัมน์ foreign key ( addess.student_id) เพื่อป้องกันหลายแถวในตารางลูก ( address) ไม่ให้เกี่ยวข้องกับแถวเดียวกันในตารางที่อ้างอิง ( student)

One-to-Many : ใช้ foreign key ในหลาย ๆ ด้านของความสัมพันธ์ที่เชื่อมโยงกลับไปที่ด้าน "หนึ่ง":

teachers: teacher_id, first_name, last_name # the "one" side
classes:  class_id, class_name, teacher_id  # the "many" side

หลายต่อหลายคน : ใช้ตารางแยก ( ตัวอย่าง ):

student: student_id, first_name, last_name
classes: class_id, name, teacher_id
student_classes: class_id, student_id     # the junction table

แบบสอบถามตัวอย่าง:

 -- Getting all students for a class:

    SELECT s.student_id, last_name
      FROM student_classes sc 
INNER JOIN students s ON s.student_id = sc.student_id
     WHERE sc.class_id = X

 -- Getting all classes for a student: 

    SELECT c.class_id, name
      FROM student_classes sc 
INNER JOIN classes c ON c.class_id = sc.class_id
     WHERE sc.student_id = Y


1
ตัวอย่างที่ดีของการที่ "ลิงก์ย้อนกลับ" มีประโยชน์ในความสัมพันธ์แบบหนึ่งต่อหนึ่งคืออะไร ขอบคุณสำหรับคำตอบที่ชัดเจนและรัดกุม
dev_feed

1
@dev_feed ในแง่ของการออกแบบฐานข้อมูลผมไม่เห็นกลับมาเชื่อมโยงให้เป็นประโยชน์ แต่ใช้ตัวอย่างข้างต้นเชื่อมโยงกลับที่สามารถลดความซับซ้อนของการหาstudentรับ address
edhedges

@NullUserException เราต้องใช้ 3 ตารางสำหรับความสัมพันธ์แบบหลายต่อกลุ่มไม่สามารถทำได้โดยสองตารางคือความสัมพันธ์แบบหลายต่อหลายกลุ่ม

1
@Cody แต่ละstudent_classesแถวควรมีความสัมพันธ์แบบหนึ่งต่อหนึ่งเท่านั้น หากstudentAอยู่ในclassAและclassBควรมีสองแถวในstudent_classesหนึ่งแถวที่มีความสัมพันธ์
NullUserException

11
ในความสัมพันธ์แบบหนึ่งต่อหนึ่งเขตข้อมูลการรวมควรไม่ซ้ำกันในตารางทั้งสอง เป็นไปได้ว่า PK ในหนึ่งตารางที่รับประกันเอกลักษณ์ แต่อาจจำเป็นต้องมีดัชนีที่ไม่ซ้ำกันในตารางอื่น
HLGEM

70

นี่คือตัวอย่างจริงของประเภทความสัมพันธ์:

หนึ่งต่อหนึ่ง (1: 1)

ความสัมพันธ์เป็นแบบหนึ่งต่อหนึ่งถ้าหากหนึ่งระเบียนจากตาราง A สัมพันธ์กับจำนวนสูงสุดหนึ่งระเบียนในตาราง B

ในการสร้างความสัมพันธ์แบบหนึ่งต่อหนึ่งคีย์หลักของตาราง B (ที่ไม่มีเร็กคอร์ดเด็กกำพร้า) ต้องเป็นคีย์รองของตาราง A (ที่มีเร็กคอร์ดเด็กกำพร้า)

ตัวอย่างเช่น:

CREATE TABLE Gov(
    GID number(6) PRIMARY KEY, 
    Name varchar2(25), 
    Address varchar2(30), 
    TermBegin date,
    TermEnd date
); 

CREATE TABLE State(
    SID number(3) PRIMARY KEY,
    StateName varchar2(15),
    Population number(10),
    SGID Number(4) REFERENCES Gov(GID), 
    CONSTRAINT GOV_SDID UNIQUE (SGID)
);

INSERT INTO gov(GID, Name, Address, TermBegin) 
values(110, 'Bob', '123 Any St', '1-Jan-2009');

INSERT INTO STATE values(111, 'Virginia', 2000000, 110);

หนึ่งต่อหลายคน (1: M)

ความสัมพันธ์เป็นแบบหนึ่งต่อหลายคนหากว่าหนึ่งระเบียนจากตาราง A สัมพันธ์กับหนึ่งหรือมากกว่าหนึ่งระเบียนในตาราง B อย่างไรก็ตามระเบียนหนึ่งในตาราง B ไม่สามารถเกี่ยวข้องกับมากกว่าหนึ่งระเบียนในตาราง A

ในการสร้างความสัมพันธ์แบบหนึ่งต่อหลายคีย์หลักของตาราง A (ตาราง "หนึ่ง") จะต้องเป็นคีย์รองของตาราง B (ตาราง "หลายคน")

ตัวอย่างเช่น:

CREATE TABLE Vendor(
    VendorNumber number(4) PRIMARY KEY,
    Name varchar2(20),
    Address varchar2(20),
    City varchar2(15),
    Street varchar2(2),
    ZipCode varchar2(10),
    Contact varchar2(16),
    PhoneNumber varchar2(12),
    Status varchar2(8),
    StampDate date
);

CREATE TABLE Inventory(
    Item varchar2(6) PRIMARY KEY,
    Description varchar2(30),
    CurrentQuantity number(4) NOT NULL,
    VendorNumber number(2) REFERENCES Vendor(VendorNumber),
    ReorderQuantity number(3) NOT NULL
);

หลายต่อหลายคน (M: M)

ความสัมพันธ์เป็นแบบกลุ่มต่อกลุ่มถ้าหากหนึ่งระเบียนจากตาราง A เกี่ยวข้องกับหนึ่งระเบียนขึ้นไปในตาราง B และในทางกลับกัน

หากต้องการสร้างความสัมพันธ์แบบกลุ่มต่อกลุ่มให้สร้างตารางที่สามชื่อว่า "ClassStudentRelation" ซึ่งจะมีคีย์หลักของทั้งตาราง A และตาราง B

CREATE TABLE Class(
    ClassID varchar2(10) PRIMARY KEY, 
    Title varchar2(30),
    Instructor varchar2(30), 
    Day varchar2(15), 
    Time varchar2(10)
);

CREATE TABLE Student(
    StudentID varchar2(15) PRIMARY KEY, 
    Name varchar2(35),
    Major varchar2(35), 
    ClassYear varchar2(10), 
    Status varchar2(10)
);  

CREATE TABLE ClassStudentRelation(
    StudentID varchar2(15) NOT NULL,
    ClassID varchar2(14) NOT NULL,
    FOREIGN KEY (StudentID) REFERENCES Student(StudentID), 
    FOREIGN KEY (ClassID) REFERENCES Class(ClassID),
    UNIQUE (StudentID, ClassID)
);

ตัวอย่างที่ 1: หมายเลข GID (6) และหมายเลข SGID (4) เพราะอะไร SGID นั้นควรเป็น (6) หรือไม่ และที่หมายเลขตัวอย่างที่ 2 (4) และหมายเลข (2) ...
obeliksz

@obeliksz อาจเป็นค่าว่างหรือไม่
หมู่วัว

ทำไมคุณถึงใช้ UNIQUE (StudentID, ClassID) ในตอนท้ายของ M: N
strix25

1
@ strix25 ในการบังคับให้หลีกเลี่ยงการซ้ำซ้อนในการสร้างแถว ClassStudentRelation เดียวกันหลายครั้งเพราะถ้าคุณไม่แน่ใจว่าทั้งกุญแจต่างประเทศ StudentID และ ClassID ไม่ซ้ำกันจะหยุดสร้างแถวใหม่ด้วย StudentID และ ClassID เดียวกันอย่างไร เนื่องจากไม่ซ้ำกันในรหัสด้านบน ดังนั้นคุณจะใช้มันเหมือนรหัสด้านบนหรือเพิ่มคีย์หลักที่มีทั้ง StudentID และ ClassID เพื่อหลีกเลี่ยงการสร้างแถวเดียวกันซ้ำใน ClassStudentRelation
Fouad Boukredine

1
@valik Data ในฐานข้อมูลทำงานโดยอ้างอิงข้อมูลที่มีอยู่และไม่สร้างข้อมูลชิ้นเดียวกันซ้ำหลายครั้งทำไมคุณต้องทำเช่นนั้น แน่นอนคุณไม่ต้องทำอย่างอื่นไม่ได้ผล โดยที่ในใจลองกลับไปที่ตัวอย่างของคุณ (เจมส์มีชีววิทยาและชีววิทยามีเจมส์) แน่นอนคุณทำได้ แต่ไม่ต้องสร้างข้อมูลอีกชิ้นที่มีอยู่แล้วในฐานข้อมูล สิ่งที่คุณต้องทำคือเพียงแค่อ้างอิงที่มีอยู่แล้วทุกครั้งที่คุณต้องการสร้างความสัมพันธ์ใด ๆ ฉันหวังว่าจะช่วย :)
Fouad Boukredine

8

นี่เป็นคำถามที่พบบ่อยมากดังนั้นผมจึงตัดสินใจที่จะเปิดคำตอบนี้เป็นบทความ

หนึ่งต่อหลายคน

ความสัมพันธ์ของตารางแบบหนึ่งต่อกลุ่มมีลักษณะดังนี้:

หนึ่งต่อหลายคน

ในระบบฐานข้อมูลเชิงสัมพันธ์ความสัมพันธ์แบบหนึ่งต่อหลายตารางจะเชื่อมโยงสองตารางตามForeign Keyคอลัมน์ในคอลัมน์ย่อยซึ่งอ้างอิงPrimary Keyแถวของตารางหลัก

ในแผนภาพตารางด้านบนpost_idคอลัมน์ในpost_commentตารางมีForeign Keyความสัมพันธ์กับคอลัมน์postรหัสตารางPrimary Key:

ALTER TABLE
    post_comment
ADD CONSTRAINT
    fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post

หนึ่งต่อหนึ่ง

ความสัมพันธ์ของตารางแบบหนึ่งต่อหนึ่งมีลักษณะดังนี้:

หนึ่งต่อหนึ่ง

ในระบบฐานข้อมูลเชิงสัมพันธ์ความสัมพันธ์แบบหนึ่งต่อหนึ่งเชื่อมโยงตารางสองตารางตามPrimary Keyคอลัมน์ในชายน์ซึ่งเป็นการForeign Keyอ้างอิงPrimary Keyแถวของตารางแม่

ดังนั้นเราสามารถพูดได้ว่าตารางลูกใช้Primary Keyร่วมกับตารางผู้ปกครอง

ในแผนภาพตารางด้านบนidคอลัมน์ในpost_detailsตารางมีForeign Keyความสัมพันธ์กับคอลัมน์postตารางด้วยid Primary Key:

ALTER TABLE
    post_details
ADD CONSTRAINT
    fk_post_details_id
FOREIGN KEY (id) REFERENCES post

หลายต่อหลายคน

ความสัมพันธ์ของตารางแบบหลายต่อกลุ่มมีลักษณะดังนี้:

หลายต่อหลายคน

ในระบบฐานข้อมูลเชิงสัมพันธ์ความสัมพันธ์แบบหลายต่อหลายตารางจะเชื่อมโยงสองตารางหลักผ่านตารางลูกซึ่งมีสองForeign Keyคอลัมน์ที่อ้างอิงPrimary Keyคอลัมน์ของตารางหลักสองตาราง

ในแผนภาพตารางด้านบนpost_idคอลัมน์ในpost_tagตารางมีForeign Keyความสัมพันธ์กับคอลัมน์postรหัสตารางด้วยPrimary Key:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post

และtag_idคอลัมน์ในpost_tagตารางมีForeign Keyความสัมพันธ์กับคอลัมน์tagid ของตารางPrimary Key:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag

3

ความสัมพันธ์แบบหนึ่งต่อหนึ่ง (1-1): นี่คือความสัมพันธ์ระหว่างคีย์หลักและคีย์ต่างประเทศ (คีย์หลักที่เกี่ยวข้องกับคีย์ต่างประเทศเพียงหนึ่งระเบียน) นี่คือความสัมพันธ์แบบหนึ่งต่อหนึ่ง

ความสัมพันธ์แบบหนึ่งต่อหลาย (1-M): นี่คือความสัมพันธ์ระหว่างความสัมพันธ์ระหว่างคีย์หลักและต่างประเทศ แต่ที่นี่คีย์หลักที่เกี่ยวข้องกับหลายระเบียน (เช่นตาราง A มีข้อมูลหนังสือและตาราง B มีผู้จัดพิมพ์หลายเล่มของหนังสือเล่มหนึ่ง)

หลายต่อหลายคน (MM):หลายต่อหลายคนมีสองมิติอธิบายอย่างเต็มที่ด้านล่างพร้อมตัวอย่าง

-- This table will hold our phone calls.
CREATE TABLE dbo.PhoneCalls
(
   ID INT IDENTITY(1, 1) NOT NULL,
   CallTime DATETIME NOT NULL DEFAULT GETDATE(),
   CallerPhoneNumber CHAR(10) NOT NULL
)
-- This table will hold our "tickets" (or cases).
CREATE TABLE dbo.Tickets
(
   ID INT IDENTITY(1, 1) NOT NULL,
   CreatedTime DATETIME NOT NULL DEFAULT GETDATE(),
   Subject VARCHAR(250) NOT NULL,
   Notes VARCHAR(8000) NOT NULL,
   Completed BIT NOT NULL DEFAULT 0
)
-- This table will link a phone call with a ticket.
CREATE TABLE dbo.PhoneCalls_Tickets
(
   PhoneCallID INT NOT NULL,
   TicketID INT NOT NULL
)

8
น่าจะดีกว่า & ชัดเจนกว่านี้ถ้าคุณเพิ่มข้อ จำกัด ของคีย์หลักและคีย์ต่างประเทศด้วย
Ashish K Gupta
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.