Eu tenho as seguintes colunas (e mais não relacionadas) em minha tabela de banco de dados MSSQL Id
: ImageUrl
e ImageId
. A combinação de ImageUrl
e ImageId
pode ocorrer várias vezes. ImageUrl
pertence ImageId
e vice-versa.
Os exemplos a seguir usam valores fictícios para maior clareza, para a tabela de banco de dados real ImageId: int e ImageUrl: nvarchar são usados como tipos de dados.
ImageId
= a
que pertence a ImageUrl
= a.com
pode ocorrer várias vezes, mas ImageId
= a
não pode ser usado para outros ImageUrl
.
ImageUrl
= a.com
pode ocorrer múltiplas vezes com o mesmo ImageId
, mas ImageUrl
= a.com
não pode ocorrer com múltiplos ImageId
como a
e b
.
Os seguintes dados devem ser possíveis:
Eu ia | ID da imagem | Imagem URL |
---|---|---|
1 | a | a.com |
2 | a | a.com |
3 | b | b.com |
Os dois exemplos a seguir não são permitidos:
Eu ia | ID da imagem | Imagem URL |
---|---|---|
1 | a | a.com |
2 | b | a.com |
Eu ia | ID da imagem | Imagem URL |
---|---|---|
1 | a | a.com |
2 | a | b.com |
Não sei e não encontrei soluções MSSQL para isso.
Pergunta: Existe uma solução para impor isso no MSSQL? E existe uma palavra/termo para esta restrição/aplicação?
Editar: isto é para meu banco de dados existente com muitos dados, onde esta tabela é a tabela "primária". Prefiro não alterar a estrutura desta tabela alterando ou removendo colunas. Adicionar colunas está bem. É por isso que a resposta de @LeppyR64 não seria uma solução para o meu caso de uso.
Como alguém sugeriu, o melhor é consertar o modelo. Muitas vezes é possível usar view + em vez de gatilhos para compatibilidade com versões anteriores.
Se não for possível e seu objetivo for evitar a adição de dados malformados, você poderá usar um gatilho:
Você provavelmente deveria adicionar um para a atualização também
Violino
Usar um modelo de banco de dados relacional teria evitado esse problema. A dificuldade de converter os dados e adaptar o aplicativo é o preço a pagar pelo design inicial incorreto.
Dito isto, você pode impor a restrição necessária ao arranjo existente usando uma visão materializada:
Teste:
Saída:
O limite para o comprimento da chave de índice clusterizado é de 900 bytes, portanto, isso só funcionará se a combinação de ImageId e ImageUrl se ajustar a isso.
Esta solução adiciona um pequeno custo a cada modificação de dados que afeta a visualização. Há também um requisito de armazenamento para as linhas materializadas. Por outro lado, você pode achar as informações da visualização úteis para outras consultas. O mecanismo de banco de dados também pode fazer uso dele.
db<> demonstração de violino
Considerações
O mecanismo de banco de dados cuida de todos os detalhes necessários para manter a visão materializada sincronizada com a tabela base.
Se você codificar sua própria solução (por exemplo, usando um gatilho), você assume a responsabilidade de cobrir todos os casos extremos que podem ocorrer sob alta simultaneidade. Isso nem sempre é trivial. Duas sessões podem verificar uma linha conflitante ao mesmo tempo, concluir que ela não existe e, em seguida, ambas inserem com base nisso, resultando em uma duplicata não detectada.
Por outro lado, a segurança extra incorporada na manutenção da visualização tem um custo para a simultaneidade potencial. Se muitas linhas na tabela base forem resumidas em uma única linha de visualização, bloqueios adicionais poderão ocorrer devido a essa 'concentração de bloqueio'. Os impasses também são uma possibilidade, embora a indexação correta possa mitigar isso.
Manter uma visão indexada normalmente é um pouco mais rápido do que um acionador porque os operadores de plano necessários para manter a visão são inseridos no plano para a instrução de alteração de dados. Um gatilho requer controle de versão de linha e sua lógica é executada em um contexto SQL separado. O custo é semelhante à execução de comandos SQL adicionais.
A visualização materializada valida todos os dados da tabela base quando ela é criada. Os gatilhos só se aplicam a linhas adicionadas ou modificadas depois que os gatilhos são criados e enquanto permanecem ativados. As inserções em massa na tabela ignorarão os gatilhos de disparo por padrão.
Todas estas são generalizações e não uma lista completa das considerações. Você precisa testar as diversas abordagens em seu ambiente. Ou faça a transição para um bom design onde nenhuma dessas brincadeiras seja necessária.
Crie uma
Images
mesa.ImageId
é a chave primária. Crie um índice exclusivo adicional naImageUrl
coluna.A tabela Data pode então ter
Id
, eImageId
como chave estrangeira para a tabela Images.