Триггер MS SQL Server для обновления рейтинга элементов и количества голосов

чтобы сделать это проще понять, я представлю ту же самую проблему, как если бы речь шла о форуме (фактическое приложение не имеет никакого отношения к форумам вообще, но я думаю, что такая параллель легче для большинства из нас понять, фактическое приложение о чем-то очень конкретном, что большинство программистов не поймут (это приложение предназначено для хардкорных графических дизайнеров)).

предположим, что существует таблица потоков, в которой хранится информация о каждом потоке форума и threadrating таблица которая хранит номинальности потока в потребителя (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, primary key), rating(float), voters (int) и некоторые другие поля, которые не имеют отношения к текущему вопросу. Таблица threadrating содержит только threadid (внешний ключ), userid (внешний ключ к первичному ключу таблицы пользователей) и рейтинг (tinyint между 1 и 5).

сообщение об ошибке "неправильный синтаксис рядом с ключевым словом "группа"."

3 ответов


во-первых, я настоятельно рекомендую вам не использовать триггеры.

если вы получаете синтаксическую ошибку, проверьте, что ваши родители сбалансированы, а также ваш begin/ends. В вашем случае, у вас есть end (В конце), но нет начала. Вы можете исправить это просто убрав end.

как только вы это исправите, вы,вероятно,получите еще несколько ошибок, таких как "столбцы x, y, z не в совокупности или группе". Это потому, что у вас есть несколько столбцов, которые не в любой. Вам нужно добавить поток.рейтинг, нить.голосов и т. д. к вашей группе или выполнить какой-то агрегат на них.

все это предполагает, что существует несколько записей с одним и тем же threadID (т. е. это не первичный ключ). Если это не дело, тогда какова цель группы?


Edit:

Я в тупике по синтаксической ошибке. Я работал над этим с парой коррелированных подзапросов. Я догадался о структуре вашего стола. поэтому измените по мере необходимости и попробуйте следующее:

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

если это то, что вы хотели, то мы можем проверить производительность/план выполнения и изменить по мере необходимости. Возможно, мы сможем заставить его работать с группой.


альтернативы триггеры

если вы обновляете данные, которые влияют на рейтинги только в нескольких выбранных местах, я бы рекомендовал обновить рейтинги непосредственно там. Факторинг логики в триггер хорош, но обеспечивает много проблемы (производительность, видимость и т. д.). Этому может помочь функция.

подумайте об этом: ваш триггер будет выполняться каждый раз, когда кто-то касается этой таблицы. Такие вещи, как количество просмотров, последние обновленные даты и т. д. выполнит этот триггер. Вы можете добавить логику к короткому замыканию триггера в этих случаях, но это быстро усложняется.


Д'ohh! Я совершенно неправильно понял ваш вопрос, и я думал, что вы спрашиваете о MySQL. Покаянием! Я оставлю Решение ниже нетронутым и отмечу его как сообщество wiki. Возможно, это будет полезно кому-то с подобной проблемой на MySQL.


MySQL триггеры are выполняется для каждой строки. Также псевдо-таблица"inserted " является соглашением Microsoft SQL Server.

MySQL использует псевдо-таблицы NEW и OLD как расширения к триггер язык.

вот решение вашей проблемы:

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

точно так же вам понадобятся триггеры для UPDATE и DELETE:

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

вы можете найти следующее значение полезная:

введение в триггеры
Википедия: триггеры DB