SQL Server 2008: Posso usar uma restrição para isso?
-
18-09-2019 - |
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?
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.
Em seguida, carregar os seus tipos de documento com o intervalo de valores válidos.
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.
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