Uma chave estrangeira pode ser NULL e / ou duplicada?

325

Por favor, esclareça duas coisas para mim:

  1. Uma chave estrangeira pode ser NULL?
  2. Uma chave estrangeira pode ser duplicada?

Por mais justo que eu saiba, NULLnão deve ser usado em chaves estrangeiras, mas em algumas aplicações minhas posso inserir NULLno Oracle e no SQL Server, e não sei por que.

geléias
fonte
1
@ Adrian: O melhor que sei é que a chave estrangeira não pode ser nula, mas está sendo nula no sql server e oracle. você pode explicar o porquê?
jams
@ Jam - leia o link na minha resposta.
JNK
11
isso não pode ser excluído porque as respostas e a pergunta são úteis. Sinta-se livre para editar a pergunta para melhorá-la.
Jeff Atwood
Divida a pergunta sobre duplicatas. Somente a questão sobre NULLs está sendo respondida abaixo.
Reinierpost

Respostas:

529

Resposta curta: Sim, pode ser NULL ou duplicada.

Quero explicar por que uma chave estrangeira pode precisar ser nula ou precisa ser única ou não exclusiva. Lembre-se primeiro de que uma chave estrangeira simplesmente exige que o valor nesse campo exista primeiro em uma tabela diferente (a tabela pai). Isso é tudo que um FK é por definição. Nulo por definição não é um valor. Nulo significa que ainda não sabemos qual é o valor.

Deixe-me dar um exemplo da vida real. Suponha que você tenha um banco de dados que armazene propostas de vendas. Suponha ainda que cada proposta tenha apenas um vendedor designado e um cliente. Portanto, sua tabela de propostas teria duas chaves estrangeiras, uma com o ID do cliente e outra com o ID do representante de vendas. No entanto, no momento em que o registro é criado, um representante de vendas nem sempre é atribuído (porque ninguém está livre para trabalhar nele ainda), portanto, o ID do cliente é preenchido, mas o ID do representante de vendas pode ser nulo. Em outras palavras, geralmente você precisa da capacidade de ter um FK nulo quando talvez não saiba seu valor no momento em que os dados são inseridos, mas você conhece outros valores na tabela que precisam ser inseridos. Para permitir nulos em um FK, geralmente tudo o que você precisa fazer é permitir nulos no campo que possui o FK. O valor nulo é separado da ideia de ser um FK.

Se é exclusivo ou não, está relacionado ao fato de a tabela ter um relacionamento um-um ou um-muitos com a tabela pai. Agora, se você tiver um relacionamento individual, é possível que você possa ter todos os dados em uma tabela, mas se a tabela estiver ficando muito ampla ou se os dados estiverem em um tópico diferente (o funcionário - exemplo de seguro que @tbone deu por exemplo), então você quer tabelas separadas com um FK. Você desejaria tornar esse FK também o PK (que garante exclusividade) ou colocar uma restrição exclusiva nele.

A maioria dos FKs é para um relacionamento de um para muitos e é isso que você obtém de um FK sem adicionar mais restrições no campo. Então você tem uma tabela de pedidos e a tabela de detalhes do pedido, por exemplo. Se o cliente solicitar dez itens ao mesmo tempo, ele terá um e dez registros de detalhes do pedido que contêm o mesmo ID do pedido que o FK.

HLGEM
fonte
13
Então, isso pretende ser melhor do que ter um vendedor falso chamado "Não atribuído"?
Thomas Weller
8
Um comentário. Os nulos deixam muito espaço para erros na consulta por pessoas que não sabem como o SQL (mis) lida com 3VL. Se um vendedor não for realmente necessário para uma determinada tabela-r, você não deve incluir esse registro. Uma tabela separada pode ser "ProposalAssignedTo" ou algo parecido, com restrições apropriadas. Um gravador de consultas pode ingressar nessa tabela e fornecer sua própria lógica para o que queremos fazer quando uma proposta não tem um vendedor. NULL não significa apenas "não sabemos" - ele pode ser usado para muitas coisas (que é por isso que é quase sempre uma má idéia)
N West
26
@ nWest, não permito que pessoas incompetentes consultem meus bancos de dados e qualquer desenvolvedor que não saiba como lidar com nulos é incompetente. Há momentos em que os dados não são conhecidos no momento da entrada inicial de dados para um campo específico, mas os outros campos são necessários naquele momento.
HLGEM
28
@ThomasWeller Fazer referência a um vendedor falso ("Não atribuído") piora o problema. Presumo que sua tabela de vendedor tenha várias colunas ...? Qual o número do seguro social do Sr. Não Atribuído? Em que departamento ele está designado? Quem é o chefe dele? Espero que você entenda meu ponto de vista: ao criar um vendedor "Não atribuído", você descobre rapidamente que trocou NULLem uma tabela por vários NULLs em uma tabela diferente.
Gili
1
@ThomasWeller Você também terá um problema se / quando precisar localizar sua interface.
Tobiv
50

1 - Sim, desde pelo menos o SQL Server 2000.

2 - Sim, desde que não seja uma UNIQUErestrição ou esteja vinculado a um índice exclusivo.

JNK
fonte
Esse link está morto.
MikeTheLiar
45

Da boca do cavalo:

Chaves estrangeiras permitem valores de chave que são todos NULL, mesmo se não houver chaves PRIMARY ou UNIQUE correspondentes

Sem restrições na chave estrangeira

Quando nenhuma outra restrição é definida na chave estrangeira, qualquer número de linhas na tabela filha pode fazer referência ao mesmo valor da chave pai. Este modelo permite nulos na chave estrangeira. ...

Restrição NOT NULL na chave estrangeira

Quando nulos não são permitidos em uma chave estrangeira, cada linha na tabela filha deve referenciar explicitamente um valor na chave pai, porque nulos não são permitidos na chave estrangeira.

Qualquer número de linhas na tabela filho pode fazer referência ao mesmo valor da chave pai, portanto, este modelo estabelece um relacionamento um para muitos entre o pai e as chaves estrangeiras. No entanto, cada linha na tabela filha deve ter uma referência a um valor de chave pai; a ausência de um valor (nulo) na chave estrangeira não é permitida. O mesmo exemplo na seção anterior pode ser usado para ilustrar esse relacionamento. No entanto, nesse caso, os funcionários devem ter uma referência a um departamento específico.

Restrição ÚNICA da Chave Estrangeira

Quando uma restrição UNIQUE é definida na chave estrangeira, apenas uma linha na tabela filha pode fazer referência a um determinado valor da chave pai. Este modelo permite nulos na chave estrangeira.

Este modelo estabelece um relacionamento individual entre o pai e as chaves estrangeiras que permite valores indeterminados (nulos) na chave estrangeira. Por exemplo, suponha que a tabela de funcionários tenha uma coluna denominada MEMBERNO, referente a um número de associação de funcionários no plano de seguro da empresa. Além disso, uma tabela denominada INSURANCE possui uma chave primária denominada MEMBERNO, e outras colunas da tabela mantêm as informações respectivas relacionadas a uma apólice de seguro de funcionário. O MEMBERNO na tabela de funcionários deve ser uma chave estrangeira e uma chave exclusiva:

  • Para impor regras de integridade referencial entre as tabelas EMP_TAB e INSURANCE (a restrição FOREIGN KEY)

  • Para garantir que cada funcionário tenha um número de associação exclusivo (a restrição de chave UNIQUE)

Restrições UNIQUE e NOT NULL na chave estrangeira

Quando as restrições UNIQUE e NOT NULL são definidas na chave estrangeira, apenas uma linha na tabela filha pode fazer referência a um determinado valor da chave pai e, como valores NULL não são permitidos na chave estrangeira, cada linha na tabela filha deve fazer referência explícita um valor na chave pai.

Veja isso:

Link do Oracle 11g

tbone
fonte
16

Sim, a chave estrangeira pode ser nula, conforme mencionado acima pelos programadores seniores ... Eu adicionaria outro cenário em que a chave estrangeira precisará ser nula ... suponha que tenhamos comentários em tabelas, fotos e vídeos em um aplicativo que permite comentários em fotos e vídeos. Na tabela de comentários, podemos ter duas chaves estrangeiras PicturesId e VideosId, juntamente com a principal Key CommentId. Portanto, quando você comentar apenas em um vídeo, o VideosId será necessário e o pictureId será nulo ... e se você comentar em uma imagem, o PictureId será obrigatório e o VideosId será nulo ...

Touseef Ahmed Awan
fonte
1
Eu acho que existe uma maneira melhor de resolver esse problema. Em vez de criar novas colunas, você pode ter duas colunas, a saber "id" e "type", que conterão a id e o nome da tabela de chaves estrangeiras. Por exemplo, id = 1, type = Picture representará o link para a tabela Picture com o id 1. A vantagem de usar esta solução é que você não precisará criar novas colunas quando comentários forem adicionados a tabelas adicionais. A desvantagem não será a restrição de chave estrangeira no nível db, mas a restrição precisará ser no nível do aplicativo.
precisa saber é o seguinte
4
@ Agent: Tivemos essa "solução" no uso da produção. Não faça isso, é terrível. Fazer consultas se torna essa bagunça, "se for do tipo 1, junte-se a esta tabela, caso contrário, junte-se a ela". Foi um pesadelo para nós. Acabamos fazendo o que esta resposta diz e criamos uma nova coluna para cada tipo de associação. Criar colunas é barato. Basicamente, a única falha é que muitas colunas tornam o Toad difícil de usar, mas isso é apenas uma falha do Toad.
user128216
1
O @FighterJet Rails fornece uma excelente estrutura ORM que lida com consultas complexas com esta solução.
Agent47DarkSoul
2
@ Agent: Talvez possa ... mas se você pode simplificar, por que torná-lo complexo? E talvez "pesadelo" fosse a palavra errada a ser usada: era apenas muito inconveniente. Não sofremos muito de problemas de integridade de dados.
user128216
7

isso depende do papel que isso foreign keydesempenha na sua relação.

  1. se isso foreign keytambém é um key attributena sua relação, não pode ser NULL
  2. se esse foreign keyé um atributo normal em sua relação, ele pode ser NULL.
shinxg
fonte
3

Aqui está um exemplo usando a sintaxe Oracle:
Primeiro vamos criar uma tabela COUNTRY

CREATE TABLE TBL_COUNTRY ( COUNTRY_ID VARCHAR2 (50) NOT NULL ) ;
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY ( COUNTRY_ID ) ;

Crie a tabela PROVINCE

CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL ,
COUNTRY_ID  VARCHAR2 (50)
);
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY ( PROVINCE_ID ) ;
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY ( COUNTRY_ID ) REFERENCES TBL_COUNTRY ( COUNTRY_ID ) ;

Isso funciona perfeitamente bem no Oracle. Observe que a chave estrangeira COUNTRY_ID na segunda tabela não possui "NOT NULL".

Agora, para inserir uma linha na tabela PROVINCE, basta especificar apenas o PROVINCE_ID. No entanto, se você optar por especificar um COUNTRY_ID também, ele já deverá existir na tabela COUNTRY.

Mouhcine
fonte
1

Por padrão, não há restrições na chave estrangeira, a chave estrangeira pode ser nula e duplicada.

ao criar uma tabela / alterar a tabela, se você adicionar alguma restrição de exclusividade ou não nula, somente ela não permitirá os valores nulos / duplicados.

nitin lalwani
fonte
0

Simplificando, os relacionamentos "Não identificados" entre Entidades fazem parte do Modelo ER e estão disponíveis no Microsoft Visio ao criar o Diagrama ER. Isso é necessário para reforçar a cardinalidade entre Entidades do tipo "zero ou mais que zero" ou "zero ou um". Observe esse "zero" na cardinalidade em vez de "um" em "um para muitos".

Agora, um exemplo de relacionamento sem identificação em que a cardinalidade pode ser "zero" (sem identificação) é quando dizemos que um registro / objeto em uma entidade - A "pode" ou "pode ​​não" ter um valor como referência ao registro / s em outra entidade-B.

Como existe a possibilidade de um registro da entidade-A se identificar com os registros de outra Entidade-B, portanto, deve haver uma coluna na Entidade-B para ter o valor de identidade do registro da Entidade-B. Essa coluna pode ser "Nula" se nenhum registro na Entidade-A identificar o registro / s (ou objeto / s) na Entidade-B.

No Paradigma Orientado a Objetos (mundo real), há situações em que um objeto da Classe B não depende necessariamente (fortemente acoplado) do objeto da classe A para sua existência, o que significa que a Classe B é fracamente acoplada à Classe Para que a classe A possa "conter" (contenção) um objeto da classe A, em oposição ao conceito de objeto da classe B, deve ter (composição) um objeto da classe A, para seu (objeto de classe) B) criação.

Do ponto de vista da Consulta SQL, você pode consultar todos os registros na entidade-B que "não são nulos" para a chave estrangeira reservada para a Entidade-B. Isso trará todos os registros com certo valor correspondente para as linhas na Entidade-A ou, alternativamente, todos os registros com valor Nulo serão os registros que não possuem nenhum registro na Entidade-A na Entidade-B.

Fakhar
fonte
-1

Eu acho que é melhor considerar a possível cardinalidade que temos nas tabelas. Podemos ter zero cardinalidade possível possível. Quando é opcional, a participação mínima de tuplas da tabela relacionada pode ser zero. Agora você enfrenta a necessidade de valores de chave estrangeira serem permitidos nulos.

Mas a resposta é que tudo depende dos negócios.

user9274383
fonte
-3

A ideia de uma chave estrangeira é baseada no conceito de referenciar um valor que já existe na tabela principal. É por isso que é chamada de chave estrangeira na outra tabela. Esse conceito é chamado de integridade referencial. Se uma chave estrangeira for declarada como um campo nulo, ela violará a própria lógica da integridade referencial. A que se refere? Só pode se referir a algo que está presente na tabela principal. Portanto, acho que seria errado declarar um campo de chave estrangeira como nulo.

SQLDev
fonte
Ele pode fazer referência a "nada" ou você ainda não conhece seu valor NULL, mas o que a integridade referencial diz é que, se fizer referência a "alguma coisa", deve estar lá.
yaxe
-7

Eu acho que a chave estrangeira de uma tabela também é a chave primária de alguma outra tabela. Portanto, não permite nulos. Portanto, não há dúvida de ter valor nulo na chave externa.

user4532553
fonte