MS SQL Server触发器更新项目评级和投票数

Lea*_*rou 6 sql-server triggers

为了使这更容易理解,我将提出完全相同的问题,就好像它是关于一个论坛(实际的应用程序根本不涉及论坛,但我认为这样的并行更容易让我们大多数人掌握,实际的应用程序是关于大多数程序员不会理解的非常具体的东西(它是一个针对硬核图形设计师的应用程序)).

假设有一个线程表存储有关每个论坛线程的信息,以及一个存储每个用户的线程评级的线程表(1-5).为了提高效率,我决定在线程表中缓存评级平均值和投票数,触发器听起来更像是一个好主意(我曾经在实际应用程序代码中做过这样的事情,但我认为触发器值得一试,尽管调试危险).

如您所知,MS SQL Server不支持每行执行一次触发器,它必须是每个语句.所以我尝试用这种方式定义它:

CREATE TRIGGER thread_rating ON threadrating
AFTER INSERT
AS
    UPDATE thread
    SET 
        thread.rating = (thread.rating * thread.voters + SUM(inserted.rating))/(thread.voters + COUNT(inserted.rating)),
        thread.voters = thread.voters + COUNT(inserted.rating)
    FROM thread
    INNER JOIN inserted ON(inserted.threadid = thread.threadid)
    GROUP BY inserted.threadid
Run Code Online (Sandbox Code Playgroud)

但我收到"GROUP BY"子句的错误(我预期).问题是,我该如何做到这一点?

对不起,如果问题很愚蠢,但这是我第一次尝试使用触发器.

附加信息:线程表将包含threadid(int,主键),rating(float),votes(int)以及对当前问题无关的其他一些字段.该threadrating表只包含threadid(外键),userid(users表主键的外键)和rating(tinyint在1和5之间).

错误消息"关键字'GROUP'附近的语法不正确."

Mic*_*ren 2

首先,我强烈建议您不要使用触发器。

如果您遇到语法错误,请检查您的括号以及begin/是否平衡ends。就你而言,你有一个end(最后)但没有开始。您可以通过删除end.

一旦解决了这个问题,您可能会收到更多错误,例如“列 x,y,z 不在聚合或分组依据中”。那是因为您有几列都不在其中。您需要将 thread. rating、thread.voters 等添加到您的组中,或者对它们执行某种聚合。

这一切都假设有多个记录具有相同的 threadID(即,它不是主键)。如果不是这样那么 group by 的目的是什么?


编辑:

我对语法错误感到困惑。我用几个相关的子查询解决了这个问题。我猜到了您的表结构,因此根据需要进行修改并尝试以下操作:

--CREATE TABLE ThreadRating (threadid int not null, userid int not null, rating int not null)
--CREATE TABLE Thread (threadid int not null, rating int not null, voters int not null)

ALTER TRIGGER thread_rating ON threadrating
AFTER INSERT
AS 

UPDATE Thread
SET Thread.rating = 
    (SELECT (Thread.Rating * Thread.Voters + SUM(I.Rating)) / (Thread.Voters + COUNT(I.Rating))
     FROM ThreadRating I WHERE I.ThreadID = thread.ThreadID)
  ,Thread.Voters = 
    (SELECT Thread.Voters + COUNT(I.Rating) 
     FROM ThreadRating I WHERE I.ThreadID = Thread.ThreadID)                         
FROM Thread
JOIN Inserted ON Inserted.ThreadID = Thread.ThreadID
Run Code Online (Sandbox Code Playgroud)

如果这就是您想要的,那么我们可以检查性能/执行计划并根据需要进行修改。我们也许还可以让它与团队一起工作。


触发器的替代方案

如果您更新的数据仅影响少数选定位置的评级,我建议您直接在那里更新评级。将逻辑分解到触发器中很好,但会带来很多问题(性能、可见性等)。这可以通过函数来​​帮助。

考虑一下:每次有人触摸该表时,您的触发器都会执行。浏览次数、上次更新日期等都会执行此触发器。在这些情况下,您可以添加逻辑来短路触发器,但它很快就会变得复杂。