Posso ter uma chave estrangeira referenciando uma coluna em uma exibição no SQL Server?


85

No SQL Server 2008 e dado

TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)

é possível definir de TableZ(A_or_B_ID, Z_Data)forma que a Z.A_or_B_IDcoluna seja restrita aos valores encontrados em ViewC? Isso pode ser feito com uma chave estrangeira na visualização?

Respostas:


110

Você não pode fazer referência a uma visão em uma chave estrangeira.


38
isso é uma limitação do servidor SQL ou é uma coisa irracional de querer?
Aaron Anodide

1
@Brian Eu também estaria interessado em saber se isso é uma limitação de um SQL Server ou algo irracional de se desejar, porque neste ponto estou prestes a emular uma visualização usando gatilhos apenas para obter suporte FK (embora esteja usando MySql )
Trenó de

4
Esta é uma boa resposta a estas perguntas de acompanhamento - stackoverflow.com/questions/3833150/…
Chris Halcrow

Não tenho certeza se essa é uma boa resposta para essas perguntas ... é sobre um DBMS diferente e diz que as visualizações foram projetadas para ocultar detalhes de esquema e conveniência do usuário. Em primeiro lugar, ok ... mas esta não seria a primeira coisa a encontrar casos de uso sólidos além do design inicial. Em segundo lugar, não sei por que um FK não faria isso. Uma visão pode ser qualquer consulta que nem mesmo precise extrair de uma tabela, pode ser um monte de constantes unidas ... uma chave estrangeira parece bastante sensata nesse caso. Se houver uma razão para não, espero algo mais profundo.
George Mauer

27

Nas edições mais antigas do SQL Server, as chaves externas eram possíveis apenas por meio de gatilhos. Você pode simular uma chave estrangeira personalizada criando um gatilho Insert que verifica se o valor inserido também aparece em uma das tabelas relevantes.


3
bem-vindo ao StackOverflow. Achei valor em sua resposta, pois fornece uma solução alternativa, mas a resposta correta é a aceita e a pergunta tem mais de 4 anos, então não estou votando, mas não queria sair sem este comentário.
jachguate de

16

Se você realmente precisa A_or_B_ID do TableZ, você tem duas opções semelhantes:

1) Adicione anuláveis A_IDe B_IDcolunas à tabela z, faça A_or_B_IDuma coluna computada usando ISNULL nessas duas colunas e adicione uma restrição CHECK de modo que apenas um A_IDouB_ID não seja nulo

2) Adicione uma coluna TableName à tabela z, restrita para conter A ou B. agora crie A_IDeB_ID como colunas computadas, que só são não nulas quando sua tabela apropriada é nomeada (usando a expressão CASE). Faça-os persistentes também

Em ambos os casos, você agora tem A_IDe B_IDcolunas que podem ter chaves estrangeiras apropriadas para as tabelas base. A diferença está em quais colunas são calculadas. Além disso, você não precisa de TableName na opção 2 acima se os domínios das 2 colunas de ID não se sobrepõem - desde que sua expressão de caso possa determinar qual domínioA_or_B_ID enquadra

(Obrigado ao comentário por corrigir minha formatação)


Coloque palavras com sublinhados em back-ticks: A_or_B_ID
Bill Karwin

Estou trabalhando para adicionar alguns recursos a um sistema legado e esta é uma ótima maneira de corrigir o antigo e o novo juntos. Obrigado!
David Gunderson


4

Existe outra opção. Trate TableA e TableB como subclasses de uma nova tabela chamada TablePrime. Ajuste os valores de ID da TabelaB para que não coincidam com os valores de ID da TabelaA. Faça do ID em TablePrime o PK e insira todos os IDs de TableA e TableB (ajustados) em TablePrime. Faça com que TableA e TableB tenham relacionamentos FK em seu PK com o mesmo ID em TablePrime.

Agora você tem o padrão de supertipo / subtipo e pode fazer restrições para TablePrime (quando quiser -A-ou-B ) ou uma das tabelas individuais (quando quiser apenas A ou apenas B ).

Se precisar de mais detalhes, pergunte. Existem variações que permitirão que você tenha certeza de que A e B são mutuamente exclusivos, ou talvez a coisa com a qual você está trabalhando possa ser os dois ao mesmo tempo. É melhor formalizar isso nos FKs, se possível.


2

É mais fácil adicionar uma restrição que faz referência a uma função definida pelo usuário que faz a verificação para você, fCheckIfValueExists (columnValue) que retorna verdadeiro se o valor existir e falso se não existir.

A vantagem é que ele pode receber várias colunas, realizar cálculos com elas, aceitar nulos e aceitar valores que não correspondem precisamente a uma chave primária ou comparar com resultados de junções.

A desvantagem é que o otimizador não pode usar todos os seus truques de chave estrangeira.


1
O lado negativo é que o otimizador não pode usar todos os seus truques de chave estrangeira ... ... e que a função será executada para cada linha que você inserir / atualizar (portanto, não muito bom para conjuntos).
jimbobmcgee

1

Desculpe, no sentido estrito da palavra, não, você não pode definir chaves estrangeiras nas visualizações. Aqui está o porquê:

InnoDB é o único mecanismo de armazenamento integrado para MySQL que apresenta chaves estrangeiras. Qualquer tabela InnoDB será registrada em information_schema.tables com engine = 'InnoDB'.

As visualizações, embora registradas em information_schema.tables, possuem um mecanismo de armazenamento NULL. Não há mecanismos no MySQL para ter chaves estrangeiras em qualquer tabela que tenha um mecanismo de armazenamento indefinido.

Obrigado!


esta pergunta é sobre sql server
George Mauer
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.