Як реалізувати відносини один на один, один на багато і багато на багато під час проектування таблиць?


281

Чи може хтось пояснити, як реалізувати відносини один на один, один на багато і багато на багато під час проектування таблиць з деякими прикладами?


Реалізація, як правило, змінюється залежно від цільової RDBMS, тому на якого постачальника ви орієнтуєтесь?
billinkc

1
це не питання домашнього завдання ... !! Я готуюсь до інтерв'ю. Тому подумав попросити тут ... Я спробував гугл, але не знайшов жодної гарної статті, де я все це пояснював за один ... !!
арсенал

Я орієнтуюся на базу даних oracle .. !!
арсенал

Ви можете прочитати цю публікацію також .... stevencalise.wordpress.com/2010/09/01/… Я б звернув пильну увагу на пункти 2 і 3.
tsells

3
@tsells Іноді вам задають питання, які не стосуються резюме або безпосередньо до вимог вакансії. Мені дали список людей, які брали інтерв'ю зі мною в одній компанії, і один був експертом з питань DB. У мене не було SQL в резюме, але я вирішив кілька простих запитів SQL. Це допомогло, і я влаштувався на роботу. Я дізнався пізніше, менеджер з найму був стурбований тим, як кандидати реагують під тиском. Вони визнають свої межі чи підробляють свій шлях? Якщо вони визнають свої межі, чи намагаються вони все-таки чи здаватись занадто рано?
Дуг Катбертсон

Відповіді:


478

Один на один: використовуйте зовнішній ключ до посилається таблиці:

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

Ви також повинні поставити унікальне обмеження на стовпчик із зовнішнім ключем ( addess.student_id), щоб запобігти тому, щоб декілька рядків у дочірній таблиці ( address) не стосувалися одного й того ж рядка у посилальній таблиці ( student).

Один на багато : Використовуйте зовнішній ключ на багатьох сторонах відносин, посилаючись назад на "одну" сторону:

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.
краями

@NullUserException нам потрібні 3 таблиці для відносин «Багато до багатьох». Хіба це не може бути зроблено двома таблицями «Відносини багатьох до багатьох».

1
@Cody Кожен student_classesрядок повинен мати лише одне співвідношення один на один. Якщо studentAв classAі classB, то в ньому повинно бути два ряди student_classes, один для яких відносини.
NullUserException

11
У відносинах один на один поле з'єднання повинно бути унікальним в обох таблицях. Ймовірно, ПК на одній таблиці, що гарантує унікальність, але може знадобитися унікальний індекс в іншій таблиці.
HLGEM

70

Ось декілька реальних прикладів типів стосунків:

Один на один (1: 1)

Відносини є один на один, якщо і лише тоді, коли один запис із таблиці А пов'язаний з максимум одним записом у таблиці Б.

Щоб встановити взаємозв'язок один на один, первинний ключ таблиці 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: М)

Відносини є множиною, якщо і лише тоді, коли один запис із таблиці А пов'язаний з одним або кількома записами в таблиці В. Однак один запис у таблиці В не може бути пов'язаний з більш ніж одним записом у таблиці А.

Для встановлення відносини "один на багато" первинний ключ таблиці А (таблиця "один") повинен бути вторинним ключем таблиці В (таблиця "багато").

Наприклад:

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)

Відносини є багато-багато-багато тоді і тільки тоді, коли один запис з таблиці А пов'язаний з одним або декількома записами в таблиці В і навпаки.

Щоб встановити взаємозв'язок між багатьма, створіть третю таблицю під назвою "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.
Фуад Букредін

1
@valik Дані в базах даних працюють, посилаючись на існуючі дані, а не створюючи один і той же фрагмент даних кілька разів, навіщо це робити? звичайно, не потрібно, інакше це не ефективно. Зважаючи на це, повернемося до вашого прикладу (у Джеймса є біологія, а в біології - Джеймс). Все, що вам потрібно зробити, - це просто посилатися на вже існуючий, коли ви хочете створити будь-які стосунки. Я сподіваюся, що це допомагає :)
Фуад Букредін

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відношення до стовпця tagідентифікатора Primary Keyтаблиці:

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

3

Відношення один до одного (1-1): це відношення між первинним та зовнішнім ключем (первинний ключ, що стосується зовнішнього ключа, лише один запис). це стосунки один до одного.

Співвідношення "Один до багатьох" (1-М): це також співвідношення між зв'язками первинного та зовнішнього ключів, але тут первинний ключ, що стосується декількох записів (тобто у таблиці A є інформація про книгу, а в таблиці B є кілька видавців однієї книги).

Багато до багатьох (ММ): багато до багатьох включає два виміри, пояснені повністю, як показано нижче зразком.

-- 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.