Roy*_*mir 6 trigger sql-server sql-server-2008-r2
我有一张Images
表,该表包含这些基本列 —
ImageId (int)
VotesUp (int)
VotesDown (int)
Run Code Online (Sandbox Code Playgroud)
每张图片都可以得到赞成票(向上、向下、收回投票)
upvotes 表有:
ImageId (int)
UserId (int)
Score (int ) [-1,0,+1]
Run Code Online (Sandbox Code Playgroud)
因此,如果 -
用户插入 +1 分数然后(如果不存在)我向upvotes
表中添加一个新行并更新表中的值Images
(用于快速获取)
用户将其分数从 +1 更改为 0,然后降低 votes up
votes up
和增加
votes down
votes up
用户将其分数从 0 更改为 -1,然后增加 votes down
用户将其分数从 -1 更改为 0 然后降低 votes down
votes down
和增加votes up
这是一个非常简单的逻辑。
这是upvotes
桌子上的触发器:
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
Run Code Online (Sandbox Code Playgroud)
它按预期工作。
那么问题出在哪里呢?
题 :
我认为这个触发器可以在没有所有这些 if/cases 的情况下简化。我只是看不到简化。
是否可以简化此触发器?
我不使用触发器,而是使用索引视图。
这样,SQL Server 自动保持数据的两个视图同步,无需编写任何触发代码。您也不必担心微妙的竞争条件和其他潜在的并发问题。
CREATE TABLE dbo.Upvotes
(
ImageId integer NOT NULL,
UserId integer NOT NULL,
Score smallint NOT NULL,
CONSTRAINT ValidScore
CHECK (Score IN (-1, 0, +1)),
CONSTRAINT PK_dbo_Upvotes__ImageId_UserId
PRIMARY KEY (ImageId, UserId)
);
GO
CREATE VIEW dbo.Images
WITH SCHEMABINDING
AS
SELECT
U.ImageId,
VotesUp = SUM(CASE WHEN U.Score = +1 THEN 1 ELSE 0 END),
VotesDown = SUM(CASE WHEN U.Score = -1 THEN 1 ELSE 0 END),
NumRows = COUNT_BIG(*)
FROM dbo.Upvotes AS U
GROUP BY
U.ImageId;
GO
CREATE UNIQUE CLUSTERED INDEX cuq
ON dbo.Images (ImageId);
Run Code Online (Sandbox Code Playgroud)
视图中的查询本质上是一个枢轴。它不是使用PIVOT
语法编写的,因为在 SQL Server 索引视图中不允许这样做。
对于 Enterprise/Developer Edition,优化器将根据成本做出使用视图索引的决定,或者扩展视图并访问基表。您可以通过NOEXPAND
提示强制使用视图索引。
在其他版本中,您必须使用NOEXPAND
提示来避免扩展视图。更喜欢使用带有索引视图的提示还有其他原因NOEXPAND
。
SELECT
I.ImageId,
I.VotesUp,
I.VotesDown
FROM dbo.Images AS I WITH (NOEXPAND);
Run Code Online (Sandbox Code Playgroud)