Eu tenho uma Images
tabela onde essa tabela tem essas colunas básicas -
ImageId (int)
VotesUp (int)
VotesDown (int)
Cada imagem pode receber votos positivos (up, down, retrair vote)
A tabela de upvotes tem:
ImageId (int)
UserId (int)
Score (int ) [-1,0,+1]
Então se -
Um usuário insere uma pontuação de +1 então (se não existir) eu adiciono uma nova linha à
upvotes
tabela e atualizo o valor naImages
tabela (para busca rápida)Um usuário altera sua pontuação de +1 para 0 e depois diminui
votes up
- Um usuário altera sua pontuação de +1 para -1 e depois diminui
votes up
e aumentavotes down
- Um usuário altera sua pontuação de 0 para +1 e depois aumenta
votes up
Um usuário altera sua pontuação de 0 para -1 e depois aumenta
votes down
Um usuário altera sua pontuação de -1 para 0 e depois diminui
votes down
- Um usuário altera sua pontuação de -1 para +1 e depois diminui
votes down
e aumentavotes up
É uma lógica bem simples.
Aqui está o gatilho na upvotes
tabela:
alter TRIGGER [dbo].[UpvotesChanged]
ON [dbo].[Upvotes]
FOR INSERT, UPDATE
AS
BEGIN
IF EXISTS( SELECT 1 FROM DELETED ) --update
BEGIN
UPDATE imgs
SET VotesUp = CASE
WHEN deleted.Score = 1 AND INSERTED.score =0 THEN ISNULL(VotesUp, 0) -1
WHEN deleted.Score = 1 AND INSERTED.score =-1 THEN ISNULL(VotesUp, 0) -1
WHEN deleted.Score = 0 AND INSERTED.score =1 THEN ISNULL(VotesUp, 0) +1
WHEN deleted.Score = -1 AND INSERTED.score =1 THEN ISNULL(VotesUp, 0) +1
ELSE ISNULL(VotesUp, 0)
END
,
VotesDown = CASE
WHEN deleted.Score = 0 AND INSERTED.score =-1 THEN ISNULL(VotesDown, 0) +1
WHEN deleted.Score = 1 AND INSERTED.score =-1 THEN ISNULL(VotesDown, 0) +1
WHEN deleted.Score = -1 AND INSERTED.score =1 THEN ISNULL(VotesDown, 0) -1
WHEN deleted.Score = -1 AND INSERTED.score =0 THEN ISNULL(VotesDown, 0) -1
ELSE ISNULL(VotesDown, 0)
END
FROM Images imgs
JOIN DELETED
ON imgs.ImageId = deleted.ImageId
JOIN INSERTED ON imgs.ImageId = INSERTED.ImageId
END
ELSE
--insert
BEGIN
UPDATE imgs
SET VotesUp = CASE
WHEN INSERTED.Score = 1
THEN ISNULL(VotesUp, 0) + 1
ELSE VotesUp
END,
VotesDown = CASE
WHEN INSERTED.Score = -1
THEN ISNULL(VotesDown, 0) + 1
ELSE VotesDown
END
FROM Images imgs
JOIN INSERTED
ON imgs.ImageId = INSERTED.ImageId
END
END
Está funcionando como esperado.
Então onde está o problema ?
Pergunta :
Acho que esse gatilho pode ser simplificado sem todos esses if's/cases . Não consigo ver a simplificação.
É possível simplificar este gatilho?
Em vez de usar um gatilho, eu usaria uma exibição indexada.
Dessa forma, as duas visualizações dos dados são mantidas automaticamente sincronizadas pelo SQL Server, sem escrever nenhum código de gatilho. Você também não precisa se preocupar com condições sutis de corrida e outros possíveis problemas de simultaneidade.
Visualização indexada
A consulta na exibição é essencialmente um pivô. Ele não é escrito usando
PIVOT
sintaxe, pois isso não é permitido em uma exibição indexada do SQL Server.Para Enterprise/Developer Edition, o otimizador tomará uma decisão baseada em custo para usar o(s) índice(s) da exibição ou expandir a exibição e acessar as tabelas base. Você pode forçar o uso dos índices de exibição com uma
NOEXPAND
dica.Em outras edições você deve usar a
NOEXPAND
dica para evitar expandir a visualização. Há outros motivos para preferir usarNOEXPAND
dicas com exibições indexadas.Exemplo