Como implementar relacionamentos um para um, um para muitos e muitos para muitos ao projetar tabelas?

281

Alguém pode explicar como implementar relacionamentos um para um, um para muitos e muitos para muitos enquanto cria tabelas com alguns exemplos?

arsenal
fonte
A implementação tende a variar com base no RDBMS de destino. Portanto, qual fornecedor você está alvejando?
billinkc
1
isso não é uma pergunta de lição de casa ... !! Estou me preparando para uma entrevista .. Então pensei em perguntar aqui ... Tentei pesquisar no Google, mas não encontrei nenhum bom artigo em que eu explique tudo isso em um ... !!
arsenal
Estou visando o banco de dados oracle .. !!
arsenal
Você pode querer ler este post, bem .... stevencalise.wordpress.com/2010/09/01/... eu iria prestar muita atenção para os pontos 2 e 3.
tsells
3
@tsells Às vezes, você recebe perguntas que não se aplicam ao conteúdo do seu currículo ou diretamente aos requisitos do trabalho. Recebi uma lista de pessoas que me entrevistariam em uma empresa e uma delas era especialista em DB. Eu não tinha SQL no meu currículo, mas atualizei algumas consultas SQL simples. Ajudou e consegui o emprego. Descobri mais tarde que o gerente de contratação estava preocupado com a forma como os candidatos respondem sob pressão. Eles admitem seus limites ou falsificam seu caminho? Se eles admitem seus limites, eles tentam de qualquer maneira ou desistem cedo demais?
Doug Cuthbertson

Respostas:

478

Um para um: use uma chave estrangeira para a tabela referenciada:

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

Você também deve colocar uma restrição exclusiva na coluna de chave estrangeira ( addess.student_id) para impedir que várias linhas na tabela filha ( address) se relacionem com a mesma linha na tabela referenciada ( student).

Um para muitos : use uma chave estrangeira no lado muitos do relacionamento, vinculando de volta ao lado "um":

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

Muitos para muitos : use uma tabela de junção ( exemplo ):

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

Consultas de exemplo:

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

NullUserException
fonte
1
Qual é um bom exemplo de quando o "link de volta" é útil no relacionamento individual? Obrigado pela resposta clara e concisa.
Dev_feed 29/05
1
@dev_feed Em termos de design do banco de dados, não vejo o link de volta como benéfico, mas usar o exemplo acima do link de volta poderia simplificar a localização de um studentdado address.
Ededges
@NullUserException, precisamos de 3 tabelas para o relacionamento Muitos-para-muitos.Não pode ser feito por duas tabelas, o Relacionamento Muitos-para-muitos.
1
@Cody Cada student_classeslinha deve ter apenas um relacionamento individual. Se studentAestiver em classAe classB, deve haver duas linhas student_classes, uma para qual relacionamento.
NullUserException
11
Em um relacionamento individual, o campo de junção deve ser exclusivo nas duas tabelas. Provavelmente, é um PK em uma tabela que garante exclusividade, mas pode ser necessário um índice exclusivo na outra tabela.
HLGEM
70

Aqui estão alguns exemplos reais dos tipos de relacionamentos:

Um para um (1: 1)

Um relacionamento é individual se e somente se um registro da tabela A estiver relacionado a um máximo de um registro na tabela B.

Para estabelecer um relacionamento um para um, a chave primária da tabela B (sem registro órfão) deve ser a chave secundária da tabela A (com registros órfãos).

Por exemplo:

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

Um para muitos (1: M)

Um relacionamento é um para muitos se, e somente se, um registro da tabela A estiver relacionado a um ou mais registros na tabela B. No entanto, um registro na tabela B não pode estar relacionado a mais de um registro na tabela A.

Para estabelecer um relacionamento um para muitos, a chave primária da tabela A (a tabela "um") deve ser a chave secundária da tabela B (a tabela "muitos").

Por exemplo:

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

Muitos-para-muitos (M: M)

Um relacionamento é muitos para muitos se e somente se um registro da tabela A estiver relacionado a um ou mais registros na tabela B e vice-versa.

Para estabelecer um relacionamento muitos para muitos, crie uma terceira tabela chamada "ClassStudentRelation", que terá as chaves primárias da tabela A e da tabela 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)
);
Arabinda Banik
fonte
1º exemplo: número GID (6) e número SGID (4), por quê? O SGID também não deveria ser (6)? E no 2º exemplo, o número (4) e número (2) ...
obeliksz
@obeliksz poderia ser nulo?
moo vaca
Por que você usaria UNIQUE (StudentID, ClassID) no final de M: N?
strix25
1
@ strix25 Para imitar evitar a repetição na criação da mesma linha ClassStudentRelation várias vezes, porque se você não garantir que as chaves estrangeiras StudentID e ClassID sejam exclusivas, o que deixa de criar uma nova linha com o mesmo StudentID e ClassID? como eles não são exclusivos no código acima. Você pode implementá-lo como o código acima ou adicionar uma chave primária que inclua StudentID e ClassID para evitar a repetição da criação da mesma linha em ClassStudentRelation.
Fouad Boukredine
1
@valik Os dados nos bancos de dados funcionam referenciando os dados existentes e não criando o mesmo pedaço de dados várias vezes, por que você faria isso? é claro que você não precisa, caso contrário, não é eficiente. Com isso em mente, voltemos ao seu exemplo (james tem biologia e biologia tem james). É claro que você pode, MAS sem criar outro dado que já exista no banco de dados. Tudo o que você precisa fazer é apenas referenciar o já existente sempre que desejar criar um relacionamento. Espero que ajude :)
Fouad Boukredine
8

Como é uma pergunta muito comum, decidi transformar essa resposta em um artigo .

Um para muitos

O relacionamento de uma para muitas tabelas é o seguinte:

Um para muitos

Em um sistema de banco de dados relacional, um relacionamento de tabela um para muitos vincula duas tabelas com base em uma Foreign Keycoluna no filho que faz referência à Primary Keylinha da tabela pai.

No diagrama da tabela acima, a post_idcoluna da post_commenttabela possui um Foreign Keyrelacionamento com a coluna do postID da tabela Primary Key:

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

Um a um

O relacionamento da tabela um para um é o seguinte:

Um a um

Em um sistema de banco de dados relacional, um relacionamento de tabela um para um vincula duas tabelas com base em uma Primary Keycoluna no filho, que também é uma Foreign Keyreferência à Primary Keylinha da tabela pai.

Portanto, podemos dizer que a tabela filha compartilha a Primary Keycom a tabela pai.

No diagrama da tabela acima, a idcoluna da post_detailstabela também possui um Foreign Keyrelacionamento com a coluna da posttabela id Primary Key:

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

Muitos para muitos

O relacionamento de tabela muitos para muitos é o seguinte:

Muitos para muitos

Em um sistema de banco de dados relacional, um relacionamento de tabela muitos para muitos vincula duas tabelas pai por meio de uma tabela filha que contém duas Foreign Keycolunas referenciando as Primary Keycolunas das duas tabelas pai.

No diagrama da tabela acima, a post_idcoluna da post_tagtabela também possui um Foreign Keyrelacionamento com a coluna do postID da tabela Primary Key:

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

E, a tag_idcoluna na post_tagtabela possui um Foreign Keyrelacionamento com a coluna de tagidentificação da tabela Primary Key:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Vlad Mihalcea
fonte
3

Relação um a um (1-1): é a relação entre chave primária e chave estrangeira (chave primária relacionada à chave estrangeira apenas um registro). esse é um relacionamento individual.

Relacionamento um para muitos (1-M): também é um relacionamento entre relacionamentos de chaves primárias e estrangeiras, mas aqui a chave primária relacionada a vários registros (por exemplo, a Tabela A possui informações sobre o livro e a Tabela B possui vários editores de um livro).

Muitos para muitos (MM): muitos para muitos inclui duas dimensões, explicadas completamente como abaixo com a amostra.

-- 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
)
Anjan Kant
fonte
8
Teria sido melhor e mais claro se você tivesse adicionado restrições de chave primária e de chave estrangeira também.
Ashish K Gupta