2009-04-15 37 views
6

爲了更容易理解,我將呈現完全相同的問題,就好像它是關於論壇一樣(實際應用程序與論壇無關所有,但我認爲這樣的並行對我們大多數人來說更容易掌握,實際的應用程序是關於大多數程序員不會理解的非常具體的東西(它是針對硬核圖形設計者的應用程序))。MS SQL Server觸發器更新項目評分和票數

讓我們假設有一個線程表存儲有關每個論壇線程和一個存儲每個用戶(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 

但是我得到了一個「GROUP BY」子句(我期望的)的錯誤。問題是,我該如何做這項工作?

對不起,如果問題很愚蠢,但這是我第一次嘗試使用觸發器。

附加信息:線程表將包含threadid(int,主鍵),rating(float),vot(int)以及其他與當前問題無關的字段。 線程表只包含threadid(外鍵),userid(用戶表的主鍵的外鍵)和rating(tinyint在1和5之間)。

錯誤消息是「關鍵字'GROUP'附近的語法不正確。」

+0

什麼是對錶的主鍵? – 2009-04-15 23:56:50

+0

發佈表DML和實際的錯誤信息也會有幫助。 – 2009-04-16 00:06:52

回答

2

首先,我強烈建議您使用觸發器。

如果您收到語法錯誤,請檢查您的夥伴平衡以及您的begin/ends。在你的情況下,你有一個end(最後),但沒有開始。你可以修復那只是刪除end

一旦你解決了這個問題,你可能會得到更多的錯誤,比如「列x,y,z不在聚合或組合中」。那是因爲你有幾列不在其中。您需要將thread.rating,thread.voters等添加到您的組中,或者對它們執行某種聚合。

這是假設有多個記錄具有相同的threadID(即它不是主鍵)。如果那不是的情況下,那麼這個小組的目的是什麼?


編輯:

我難倒了語法錯誤。我用一些相關的子查詢來解決它。我在你的表結構猜到所以根據需要修改和嘗試這個辦法:

--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 

如果這是你想要的東西,那麼我們可以檢查性能/執行計劃,並根據需要修改。我們或許可以通過它與團隊合作。


替代觸發器

如果要更新,在只有少數選擇地影響收視率,我建議你更新的收視率有直接的數據。將邏輯分解爲觸發器很不錯,但會帶來很多問題(性能,可視性等)。這可以通過函數來​​幫助。

考慮一下:觸發器會在每次有人觸摸該表時執行。像查看計數,上次更新的日期等將執行此觸發器。在這些情況下,您可以添加邏輯來短接觸發器,但它很快變得複雜。

1

您可能會發現下面的閱讀有幫助:

An introduction to Triggers
Wikipedia: DB Triggers

+0

我一直在閱讀關於觸發器和SQL Server的方法,至少在過去3個小時內完成它們......沒有什麼能夠幫助我的特殊情況:( – 2009-04-16 00:13:19

+0

哇,太糟糕了!我看我是否能找到一些更好的鏈接 – Kredns 2009-04-16 00:20:42

2

D'ohh!我完全誤解了你的問題,我以爲你在問MySQL。 Mea culpa!我將保留下面的解決方案,並將其標記爲社區wiki。也許這對MySQL上類似問題的人會有用。


MySQL的觸發每行執行。此外,僞表「inserted」是Microsoft SQL Server約定。

MySQL使用僞表NEWOLD作爲trigger language的擴展。

這裏是你的問題的解決方案:

CREATE TRIGGER thread_rating 
    AFTER INSERT ON threadrating 
    FOR EACH ROW 
BEGIN 
    UPDATE thread 
    SET rating = (rating*voters + NEW.rating)/(voters+1), 
     voters = voters + 1 
    WHERE threadid = NEW.threadid; 
END 

同樣你需要觸發的UPDATEDELETE

CREATE TRIGGER thread_rating 
    AFTER UPDATE ON threadrating 
    FOR EACH ROW 
BEGIN 
    UPDATE thread 
    SET rating = (rating*voters - OLD.rating + NEW.rating)/voters, 
    WHERE threadid = NEW.threadid; 
END 

CREATE TRIGGER thread_rating 
    AFTER DELETE ON threadrating 
    FOR EACH ROW 
BEGIN 
    UPDATE thread 
    SET rating = (rating*voters - OLD.rating)/(voters-1), 
     voters = voters - 1 
    WHERE threadid = OLD.threadid; 
END