Existem três maneiras básicas de resolver esse tipo de problema, pois as restrições CHECK não podem ser baseadas em uma consulta.
Opção 1:acionadores
A abordagem mais simplista seria colocar um gatilho em TANK que consulta TANKS e lança uma exceção se o LEVEL exceder CAPACITY. O problema com esse tipo de abordagem simplista, porém, é que é quase impossível lidar com problemas de simultaneidade corretamente. Se a sessão 1 diminuir a CAPACITY, a sessão 2 aumentará o LEVEL e, em seguida, ambas as transações forem confirmadas, os gatilhos não poderão detectar a violação. Isso pode não ser um problema se uma ou ambas as tabelas raramente forem modificadas, mas em geral será um problema.
Opção 2:visualizações materializadas
Você pode resolver o problema de simultaneidade criando uma visão materializada ON COMMIT que une a tabela TANK e TANKS e, em seguida, criando uma restrição CHECK na visão materializada que verifica se o LEVEL <=CAPACITY. Você também pode evitar armazenar os dados duas vezes fazendo com que a visualização materializada contenha apenas dados que violariam a restrição. Isso exigirá logs de visualização materializados em ambas as tabelas base, o que adicionará um pouco de sobrecarga às inserções (embora menos do que usar gatilhos). Empurrar a verificação para o tempo de confirmação resolverá o problema de simultaneidade, mas apresenta um pouco de problema de gerenciamento de exceção, pois a operação COMMIT agora pode falhar porque a atualização da visualização materializada falhou. Seu aplicativo precisaria ser capaz de lidar com esse problema e alertar o usuário sobre esse fato.
Opção 3:alterar o modelo de dados
Se você tem um valor na tabela A que depende de um limite na tabela B, isso pode indicar que o limite em B deve ser um atributo da tabela A (em vez de ou além de ser um atributo da tabela B). Depende das especificidades do seu modelo de dados, é claro, mas geralmente vale a pena considerar.