Jak wdrożyć relacje jeden do jednego, jeden do wielu i wiele do wielu podczas projektowania tabel?


281

Czy ktoś może wyjaśnić, jak wdrożyć relacje jeden do jednego, jeden do wielu i wiele do wielu podczas projektowania tabel z kilkoma przykładami?


Wdrożenie może się różnić w zależności od docelowego RDBMS, więc do którego dostawcy kierujesz reklamy?
billinkc

1
to nie jest zadanie domowe ... !! Przygotowuję się do rozmowy kwalifikacyjnej. Pomyślałam więc, że zapytam tutaj ... Próbowałem google, ale nie znalazłem żadnego dobrego artykułu, w którym wyjaśnię to wszystko w jednym ... !!
arsenał

Celuję w bazę danych Oracle… !!
arsenał

Możesz także przeczytać ten post .... stevencalise.wordpress.com/2010/09/01/ ... Chciałbym zwrócić szczególną uwagę na punkty 2 i 3.
sprzedaje

3
@tsells Czasami zadawane są pytania, które nie dotyczą tego, co znajduje się w twoim życiorysie lub bezpośrednio do wymagań pracy. Dostałem listę osób, które przeprowadziłyby ze mną wywiad w jednej firmie, a jedna była ekspertem od DB. Nie miałem SQL w moim życiorysie, ale spreparowałem kilka prostych zapytań SQL. Pomogło i dostałem pracę. Dowiedziałem się później, że kierownik ds. Rekrutacji martwił się, jak kandydaci reagują pod presją. Czy przyznają się do swoich ograniczeń, czy udają? Jeśli przyznają się do swoich ograniczeń, czy mimo to próbują, czy też poddają się zbyt wcześnie?
Doug Cuthbertson,

Odpowiedzi:


478

Jeden do jednego: użyj klucza obcego do tabeli, do której istnieje odwołanie:

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

Należy także nałożyć unikalne ograniczenie na kolumnę klucza obcego ( addess.student_id), aby zapobiec powiązaniu wielu wierszy w tabeli potomnej ( address) z tym samym wierszem w tabeli, do której istnieje odwołanie ( student).

Jeden do wielu : użyj klucza obcego po wielu stronach relacji, łącząc się z powrotem z jednej strony:

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

Wiele do wielu : użyj tabeli połączeń ( przykład ):

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

Przykładowe zapytania:

 -- 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
Jaki jest dobry przykład sytuacji, w której „link zwrotny” jest użyteczny w relacji jeden do jednego? Dzięki za jasną i zwięzłą odpowiedź.
dev_feed

1
@dev_feed Jeśli chodzi o projekt bazy danych, nie widzę, aby link był korzystny, ale użycie powyższego przykładu może uprościć znalezienie studentdanego address.
edhedges

@NullUserException czy potrzebujemy 3 tabel do relacji wiele do wielu. Nie można tego zrobić za pomocą dwóch tabel relacji wiele do wielu.

1
@Cody Każdy student_classeswiersz powinien mieć tylko jedną relację jeden do jednego. Jeśli studentAjest w, classAi classBpowinny być dwa wiersze, w student_classesjednym dla których relacji.
NullUserException

11
W relacji jeden do jednego pole łączenia powinno być unikalne w obu tabelach. Prawdopodobnie jest to PK na jednym stole, co gwarantuje unikalność, ale może wymagać unikalnego indeksu na drugim stole.
HLGEM

70

Oto kilka przykładów rzeczywistych rodzajów relacji:

Jeden do jednego (1: 1)

Relacja jest jeden do jednego wtedy i tylko wtedy, gdy jeden rekord z tabeli A jest powiązany z maksymalnie jednym rekordem w tabeli B.

Aby ustanowić relację jeden-do-jednego, klucz podstawowy tabeli B (bez rekordu osieroconego) musi być kluczem dodatkowym tabeli A (z rekordami osieroconymi).

Na przykład:

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

Jeden do wielu (1: M)

Relacja jest jeden do wielu wtedy i tylko wtedy, gdy jeden rekord z tabeli A jest powiązany z jednym lub większą liczbą rekordów w tabeli B. Jednak jeden rekord w tabeli B nie może być powiązany z więcej niż jednym rekordem w tabeli A.

Aby ustanowić relację jeden do wielu, klucz podstawowy tabeli A (tabela „jeden”) musi być kluczem dodatkowym tabeli B (tabela „wielu”).

Na przykład:

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

Wiele do wielu (M: M)

Relacja jest wiele do wielu wtedy i tylko wtedy, gdy jeden rekord z tabeli A jest powiązany z jednym lub większą liczbą rekordów w tabeli B i odwrotnie.

Aby ustanowić relację wiele do wielu, utwórz trzecią tabelę o nazwie „ClassStudentRelation”, która będzie zawierała klucze podstawowe zarówno tabeli A, jak i tabeli 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)
);

Pierwszy przykład: numer GID (6) i numer SGID (4), dlaczego? Czy SGID nie powinien być również (6)? A na drugim przykładzie numer (4) i numer (2) ...
obeliksz

@obeliksz może być zerowy?
krowa moo

Dlaczego miałbyś używać UNIQUE (StudentID, ClassID) na końcu M: N?
strix25

1
@ strix25 Aby wymusić unikanie powtarzania przy tworzeniu tego samego wiersza ClassStudentRelation wiele razy, ponieważ jeśli nie upewnisz się, że oba klucze obce StudentID i ClassID są unikalne, co przestanie tworzyć nowy wiersz z tym samym StudentID i ClassID? ponieważ nie są one unikalne w powyższym kodzie. Więc albo zaimplementuj go jak w powyższym kodzie, albo dodaj klucz podstawowy, który zawiera zarówno StudentID, jak i ClassID, aby uniknąć powtarzania tworzenia tego samego wiersza w ClassStudentRelation.
Fouad Boukredine

1
@valik Dane w bazach danych działają poprzez odwoływanie się do istniejących danych, a nie wielokrotne tworzenie tego samego kawałka danych, dlaczego miałbyś to zrobić? oczywiście nie musisz, w przeciwnym razie nie będzie to wydajne. Mając to na uwadze, wróćmy do twojego przykładu (James ma biologię, a biologia ma Jamesa). Oczywiście możesz, ALE bez tworzenia kolejnego elementu danych, który już istnieje w bazie danych. Wszystko, co musisz zrobić, to po prostu odwołać się do już istniejącego, gdy chcesz utworzyć dowolną relację. Mam nadzieję, że to pomoże :)
Fouad Boukredine

8

To bardzo częste pytanie, dlatego postanowiłem zamienić tę odpowiedź w artykuł .

Jeden za dużo

Relacja tabeli jeden do wielu wygląda następująco:

Jeden za dużo

W systemie relacyjnych baz danych relacja jeden do wielu łączy dwie tabele na podstawie Foreign Keykolumny w elemencie potomnym, która odwołuje się Primary Keydo wiersza tabeli nadrzędnej.

Na powyższym diagramie tabeli post_idkolumna w post_commenttabeli ma Foreign Keyzwiązek z kolumną postidentyfikatora tabeli Primary Key:

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

Jeden na jednego

Relacja tabeli jeden do jednego wygląda następująco:

Jeden na jednego

W systemie relacyjnej bazy danych relacja jeden-do-jednego tabeli łączy dwie tabele na podstawie Primary Keykolumny w elemencie potomnym, która jest również Foreign Keyodniesieniem do Primary Keywiersza tabeli nadrzędnej.

Dlatego możemy powiedzieć, że tabela potomna dzieli się Primary Keyz tabelą nadrzędną.

Na powyższym schemacie tabeli idkolumna w post_detailstabeli ma również Foreign Keyzwiązek z kolumną posttabeli id Primary Key:

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

Wiele do wielu

Relacja wielu do wielu wygląda następująco:

Wiele do wielu

W systemie relacyjnej bazy danych relacja wiele do wielu łączy dwie tabele nadrzędne za pośrednictwem tabeli podrzędnej, która zawiera dwie Foreign Keykolumny odwołujące się do Primary Keykolumn dwóch tabel nadrzędnych.

Na powyższym diagramie tabeli post_idkolumna w post_tagtabeli ma również Foreign Keyzwiązek z kolumną postidentyfikatora tabeli Primary Key:

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

I tag_idkolumna w post_tagtabeli ma Foreign Keyzwiązek z kolumną tagidentyfikatora tabeli Primary Key:

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

3

Relacja jeden do jednego (1-1): Jest to relacja między kluczem podstawowym a kluczem obcym (klucz podstawowy związany z kluczem obcym tylko jeden rekord). jest to relacja jeden do jednego.

Relacja jeden do wielu (1-M): Jest to także relacja między kluczem podstawowym a kluczem obcym, ale tutaj klucz podstawowy dotyczy wielu rekordów (tj. Tabela A zawiera informacje o książce, a Tabela B ma wielu wydawców jednej książki).

Wiele do wielu (MM): Wiele do wielu obejmuje dwa wymiary, wyjaśnione w pełni jak poniżej z próbką.

-- 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
Byłoby lepiej i wyraźniej, gdybyś dodał również ograniczenia klucza podstawowego i klucza obcego.
Ashish K Gupta
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.