Мне нужно обновить таблицу video_upload после вставки строки в таблицу video_ratings. Прежде чем сделать это, мне нужно получить количество столбцов RATINGS, а затем выполнить обновление, используя это значение. Необходимая логика указана ниже.
Таблица video_upload
CREATE TABLE `video_upload` (
`ID` int(10) NOT NULL,
`USER_ID` int(10) NOT NULL,
`VIDEO_NAME` varchar(75) COLLATE utf32_sinhala_ci NOT NULL,
`VIDEO_URL` varchar(100) COLLATE utf32_sinhala_ci DEFAULT NULL,
`PIC1_URL` varchar(100) COLLATE utf32_sinhala_ci DEFAULT NULL,
`PIC2_URL` varchar(100) COLLATE utf32_sinhala_ci DEFAULT NULL,
`PIC3_URL` varchar(100) COLLATE utf32_sinhala_ci DEFAULT NULL,
`ATT_URL` varchar(100) COLLATE utf32_sinhala_ci DEFAULT NULL,
`TYPE` varchar(7) COLLATE utf32_sinhala_ci NOT NULL,
`DESCRIPTION` varchar(2000) COLLATE utf32_sinhala_ci NOT NULL,
`IsAPPROVED` int(1) NOT NULL DEFAULT '0',
`RATE_BAD` int(10) NOT NULL,
`RATE_AVERAGE` int(10) NOT NULL,
`RATE_GOOD` int(10) NOT NULL,
`RATE_BEST` int(10) NOT NULL,
`UPLOADED_ON` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UPDATED_ON` timestamp NOT NULL ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf32 COLLATE=utf32_sinhala_ci;
Таблица video_ratings
CREATE TABLE `video_ratings` (
`VID_ID` int(10) NOT NULL,
`STU_ID` int(10) NOT NULL,
`RATINGS` int(1) NOT NULL,
`RATED_ON` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UPDATED_ON` timestamp NOT NULL ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf32 COLLATE=utf32_sinhala_ci;
Планирую сделать это с помощью триггера. Я также нашел в Интернете код триггера mysql.
//Rating count trigger
create trigger rate_count_update
after insert on video_ratings for each row begin
DECLARE updatecount INT;
set updatecount = ( select count(RATINGS) AS TOTAL from video_ratings where RATINGS='0' AND RATINGS='1' AND RATINGS='2' AND RATINGS='3' );
if updatecount=4
then
update video_upload set RATE=TOTAL;
end if;
end//
Но я не смог изменить его в соответствии с моими требованиями. Пожалуйста, помогите с этим.
Привет, @RubioRic, извини, что плохо. Я обновил вопрос. Пожалуйста, обратитесь.
Я ожидал увидеть СТАРУЮ. или НОВЫЙ. значения в триггере обновления.
Обе эти таблицы заслуживают определения ПЕРВИЧНОГО КЛЮЧА. И также похоже, что VID_ID
в video_ratings
- это ссылка внешнего ключа на столбец ID
в video_upload
.
Пара замечаний ...
Я могу с уверенностью гарантировать, что не будет НИКАКИХ строк, удовлетворяющих условиям
FROM video_ratings
WHERE RATINGS='0'
AND RATINGS='1'
AND RATINGS='2'
Подумай об этом. Если одно из этих условий (сравнений) оценивается как ИСТИНА, тогда другие сравнения будут оцениваться как ЛОЖЬ, и
TRUE AND FALSE AND FALSE
будет оцениваться как ЛОЖЬ.
Таким образом, агрегат COUNT () для этого оператора будет оцениваться как 0.
В этом заявлении UPDATE
update video_upload set RATE=TOTAL;
если все прошло успешно, это обновит строку каждый в таблице video_upload. Похоже, мы хотели бы обновить только строку один в таблице video_upload, строку со значением ID
, которое соответствует VID_ID
строки, которую мы только что вставили в таблицу videos_ratings
.
Мы можем получить значение столбца VID_ID
только что вставленной строки, указав
NEW.VID_ID
в корпусе спускового крючка. Вероятно, нам нужен оператор обновления, который выглядит примерно так:
UPDATE video_upload v
SET ...
WHERE v.ID = NEW.VID_ID ;
Если мы хотим присвоить значения столбцам RATE_BAD
, RATE_AVERAGE
, RATE_GOOD
и RATE_BEST
, нам понадобится предложение SET для ссылки на эти столбцы ...
UPDATE video_upload v
SET v.RATE_BAD = some_expr
, v.RATE_AVERAGE = another_expr
, v.RATE_GOOD = expr_for_good
, v.RATE_BEST = expr_for_best
WHERE v.ID = NEW.VID_ID ;
Возможно, мы хотели сделать что-то вроде этого, чтобы получить количество оценок и сохранить их в локальных переменных, чтобы мы могли ссылаться на них позже в триггере.
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = NEW.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
следовать за
Я рекомендую этот шаблон для имен триггеров: table_name
+ _suffix
где _suffix
- это одно из '_ad', '_ai', '_au', '_bd', '_bi', '_bu' (для после / до удаления / вставки / обновления)
Следование этому соглашению об именах позволяет избежать конфликтов имен, и когда мы будем искать триггеры в таблице, мы будем знать, где их найти. Если перечислить триггеры в алфавитном порядке, все триггеры для данной таблицы будут сгруппированы вместе по table_name (в основном). (Крайний случай, когда у нас есть вероятность некоторого смешения, это имя таблицы, которое начинается с имени другой таблицы, за которым следует _a .. или _b ..)
(На ранней стадии разработки, когда у вас есть две таблицы и полдюжины триггеров, преимущество такого соглашения об именах неочевидно. Но оно становится очевидным, когда база данных содержит множество таблиц и триггеров.)
Также обратите внимание, что MySQL поддерживает только один триггер для каждого из BEFORE / AFTER INSERT / UPDATE / DELETE в данной таблице.
Используйте локальные переменные вместо пользовательских переменных, если нет особой причины для использования пользовательской переменной.
DELIMITER $$
DROP TRIGGER IF EXISTS video_ratings_ad$$
CREATE TRIGGER video_ratings_ad
AFTER DELETE ON video_ratings
FOR EACH ROW
BEGIN
-- declare local variables
DECLARE li_cnt_r0 BIGINT;
DECLARE li_cnt_r1 BIGINT;
DECLARE li_cnt_r2 BIGINT;
DECLARE li_cnt_r3 BIGINT;
-- get counts of ratings for specific VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = OLD.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = OLD.VID_ID
;
END$$
DROP TRIGGER IF EXISTS video_ratings_ai$$
CREATE TRIGGER video_ratings_ai
AFTER UPDATE ON video_ratings
FOR EACH ROW
BEGIN
-- declare local variables
DECLARE li_cnt_r0 BIGINT;
DECLARE li_cnt_r1 BIGINT;
DECLARE li_cnt_r2 BIGINT;
DECLARE li_cnt_r3 BIGINT;
-- get counts of ratings for specific VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = NEW.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = NEW.VID_ID
;
END$$
DROP TRIGGER IF EXISTS video_ratings_au$$
CREATE TRIGGER video_ratings_au
AFTER UPDATE ON video_ratings
FOR EACH ROW
BEGIN
-- declare local variables
DECLARE li_cnt_r0 BIGINT;
DECLARE li_cnt_r1 BIGINT;
DECLARE li_cnt_r2 BIGINT;
DECLARE li_cnt_r3 BIGINT;
IF( OLD.RATINGS <=> NEW.RATINGS
-- if VID_ID and RATINGS is not changed, we can skip getting counts
IF( NEW.VID_ID <=> OLD.VID_ID AND NEW.RATINGS <=> OLD.RATINGS )
THEN BEGIN END
ELSE
-- get counts of ratings for OLD.VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = OLD.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = OLD.VID_ID
;
IF( NEW.VID_ID <=> OLD.VID_ID )
THEN BEGIN END
ELSE
-- get counts of ratings for specific VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = NEW.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = NEW.VID_ID
;
END IF;
END IF;
END$$
DELIMITER ;
Привет, @ spencer7593, я изменил триггер, как указано ниже, но при запуске триггера возникает ошибка «Неизвестная системная переменная 'updatecount'». Колуд, пожалуйста, помоги мне. ~~ создать триггер after_videor_update перед обновлением video_ratings для каждой строки begin set updatecount = (выберите count (RATINGS) AS BAD_TOTAL из video_ratings, где RATINGS = '0'); обновить video_upload SET RATE_BAD = updatecount, где USER_ID = NEW.STU_ID AND ID = NEW.VID_ID; конец ~~
Мне кажется, что updatecount
не объявлен как локальная переменная. Но зачем делать заявление SET
, когда мы можем сделать SELECT ... INTO
? И почему мы не получаем подсчет всех четырех оценок одним махом? И почему бы не обновить все четыре столбца в video_upload
с помощью одного выполнения оператора? Почему мы не квалифицируем ссылки на столбцы? И почему мы включаем условие сопоставления STU_ID
с USER_ID
... разве STU_ID
не является пользователем, который выставляет оценку, и не ожидаем ли мы, что это будет отличаться от пользователя, который загрузил видео? Разве нам не нужен триггер AFTER, а не триггер BEFORE?
А пока не могли бы вы помочь мне с триггером единой ставки. После некоторых модификаций я успешно сохранил триггер, но он не дал мне ожидаемых результатов. любые советы плз. ~~ DELIMITER $$ СОЗДАТЬ ТРИГГЕР after_videor_update ПОСЛЕ ОБНОВЛЕНИЯ video_ratings ДЛЯ КАЖДОЙ СТРОКИ НАЧАТЬ УСТАНОВИТЬ @updatecount
= (выберите count (RATINGS) AS BAD_TOTAL из video_ratings, где RATINGS = '0'); обновить video_upload SET RATE_BAD = `@ updatecount`, где USER_ID = NEW.STU_ID AND ID = NEW.VID_ID; END $$ DELIMITER; ~~
Вы должны знать, что этот сайт работает не так. Вы должны настаивать на этих примерах триггеров и возвращаться с конкретной ошибкой.