Pergunta

Eu tenho uma tabela com três campos, User, City e Country, onde exatamente um dos campos devem ser não-NULL em todos os momentos. Posso usar uma restrição de SQL para este ou eu deveria repensar o que estou fazendo?

O cenário é que meu banco de dados deve conter documentos que podem ser ligados a usuários, cidades ou países. Assim, uma linha nesta tabela contém exatamente um documento para qualquer um usuário, uma cidade ou um país. No entanto, deve ser capaz de procurar todos os documentos, bem como, independentemente do que entidade foi "anexado" a.

A razão que eu não estou usando três tabelas diferentes em vez disso é que eu quero evitar ter que JOIN as três tabelas na busca de documentos em todos os três locais. Eu estou imaginando que o tipo de desnormalização Eu estou tentando usar aqui vai melhorar o desempenho, mas não tenho certeza.

Os pensamentos?

Foi útil?

Solução

Se eu entendi corretamente, o seguinte SQL deve adicionar a restrição que você está procurando:

ALTER TABLE YourTableName
ADD CONSTRAINT CK_TestNullCount 
    CHECK (Case When [user] is NULL Then 0 Else 1 End 
           + Case When City Is NULL Then 0 Else 1 End 
           + Case When Country Is NULL Then 0 Else 1 End = 1)

Outras dicas

Não tenho certeza se você pode fazê-lo com uma restrição CHECK - Estou jogado ao redor, mas nada parece realmente trabalho no final: - (

Mas você pode sempre criar um INSTEAD OF INSERT (e possivelmente um INSTEAD OF UPDATE) gatilho na tabela para verificar estas condições, e se eles não estão satisfeitas, lançar uma exceção usando RAISERROR ea linha não será inserido (ou atualizado) .

Eu sugiro ficar com o cenário FK. Aqui está como eu iria garantir que um documento está vinculado a um, e apenas um DocumentType (o que você está chamando-attached to).

Aqui está uma relação muito simplificada. Eu sei que você já tem as 3 colunas em sua tabela de documentos, mas considere fazer que uma FK. text alt

Em seguida, carregar os seus tipos de documento com o intervalo de valores válidos.

text alt

Ao inserir dados, você estará escrevendo o tipo varchar, ao invés de um int. Isto não deve causar perf problemas, e irá ajudá-lo em relatórios, etc com o esquema desnormalizada.

text alt

Coloque-as em uma única Locais tabela com colunas LocationID, LocationName, e (se necessário) LocationType (User, cidade, país). Você só precisa de uma única juntar-se a descobrir a "localização" do documento e você não precisa se preocupar em qual campo para selecionar para obter o nome do local.

Com esta técnica, você pode impor a "uma e somente uma" exigência local com um simples não-nula restrição de chave estrangeira.

Por que você não tem duas colunas, uma chamada LocationID e um chamado LocationTypeId. Você pode então esquerda juntar-se em todas as três tabelas:

SELECT COALESCE(User.Name, City.Name, Country.Name) 
FROM Location
INNER JOIN LocationType ON Location.LocationTypeId = LocationType.LocationTypeId
LEFT JOIN User ON Location.LocationId = User.Id AND Location.LocationTypeId = 1
LEFT JOIN City ON Location.LocationId = City.Id AND Location.LocationTypeId = 2
LEFT JOIN Country ON Location.LocationId = Country.Id AND Location.LocationTypeId = 3
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top