Триггер 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