Mysql обновляет другую таблицу с помощью триггера

Мне нужно обновить таблицу video_upload после вставки строки в таблицу video_ratings. Прежде чем сделать это, мне нужно получить количество столбцов RATINGS, а затем выполнить обновление, используя это значение. Необходимая логика указана ниже.

  1. возьмите счетчик всех нулей из video_ratings и обновите столбец RATE_BAD в video_upload.
  2. возьмите счетчик всех единиц из video_ratings и обновите столбец video_upload RATE_AVERAGE.
  3. считать все 2 секунды из video_ratings и обновить столбец RATE_GOOD в video_upload.
  4. считать все 3 секунды из video_ratings и обновить столбец RATE_BEST в video_upload.

Таблица 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 02.05.2018 16:54

Привет, @RubioRic, извини, что плохо. Я обновил вопрос. Пожалуйста, обратитесь.

Eshan Gurusinghe 02.05.2018 16:59

Я ожидал увидеть СТАРУЮ. или НОВЫЙ. значения в триггере обновления.

P.Salmon 02.05.2018 17:02

Обе эти таблицы заслуживают определения ПЕРВИЧНОГО КЛЮЧА. И также похоже, что VID_ID в video_ratings - это ссылка внешнего ключа на столбец ID в video_upload.

spencer7593 02.05.2018 18:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
4
53
1

Ответы 1

Пара замечаний ...

Я могу с уверенностью гарантировать, что не будет НИКАКИХ строк, удовлетворяющих условиям

  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; конец ~~

Eshan Gurusinghe 02.05.2018 18:36

Мне кажется, что updatecount не объявлен как локальная переменная. Но зачем делать заявление SET, когда мы можем сделать SELECT ... INTO? И почему мы не получаем подсчет всех четырех оценок одним махом? И почему бы не обновить все четыре столбца в video_upload с помощью одного выполнения оператора? Почему мы не квалифицируем ссылки на столбцы? И почему мы включаем условие сопоставления STU_ID с USER_ID ... разве STU_ID не является пользователем, который выставляет оценку, и не ожидаем ли мы, что это будет отличаться от пользователя, который загрузил видео? Разве нам не нужен триггер AFTER, а не триггер BEFORE?

spencer7593 02.05.2018 18:51

А пока не могли бы вы помочь мне с триггером единой ставки. После некоторых модификаций я успешно сохранил триггер, но он не дал мне ожидаемых результатов. любые советы плз. ~~ 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; ~~

Eshan Gurusinghe 03.05.2018 11:23

Другие вопросы по теме