MySQL Ошибка, когда триггер вызывает процедуру - PullRequest
2 голосов
/ 08 ноября 2011

У меня есть таблица (ft_ttd), и я хочу отсортировать ее по убыванию (num) и вставить рейтинговые числа в столбец рейтинга.

Исходная таблица http://dl.dropbox.com/u/3922390/2.png

Нечто подобное:

Таблица результатов http://dl.dropbox.com/u/3922390/1.png

Я создал процедуру.

CREATE PROCEDURE proc_ft_ttd_sort  
BEGIN   

CREATE TEMPORARY TABLE ft_ttd_sort
(id int (2),  
num int (3),  
rating int (2) AUTO_INCREMENT PRIMARY KEY);    

INSERT INTO ft_ttd_sort (id, num)   SELECT id, num FROM ft_ttd ORDER BY num DESC;    
TRUNCATE TABLE ft_ttd;   
INSERT INTO ft_ttd SELECT * FROM ft_ttd_sort;  
DROP TABLE ft_ttd_sort;   
END;

Когда я это называю - это прекрасно работает.

CALL proc_ft_ttd_sort;

После этого я создал триггер, вызывающий эту процедуру.

CREATE TRIGGER au_ft_ttd_fer AFTER UPDATE ON ft_ttd FOR EACH ROW 
BEGIN
CALL proc_ft_ttd_sort(); 
END;

Теперь каждый раз, когда я обновляю таблицу ft_ttd, у меня появляется ошибка.

UPDATE ft_ttd SET num = 9 WHERE id = 3;
ERROR 1422 (HY000): Explicit or implicit commit is not allowed in stored function ortrigger.

Есть идеи, как заставить это работать? Может быть, этот процесс можно оптимизировать? Спасибо!

Ответы [ 2 ]

2 голосов
/ 08 ноября 2011

Оператор create table является неявным коммитом, так как он является DDL. По сути, ответ таков: вы не можете создать таблицу в триггере.

http://dev.mysql.com/doc/refman/5.0/en/stored-program-restrictions.html

1 голос
/ 08 ноября 2011

Триггеры не могут этого сделать

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

Во-вторых, вам действительно нужен триггер уровня оператора, а не FOR EACH ROW - нетнужно пересортировать всю таблицу для каждой затронутой строки - но это не поддерживается в MySQL 5 .

Динамически вычислять "rating"

Так ... это так?достаточно просто вычислить rating динамически, используя обходной путь MySQL ROW_NUMBER () ?

-- ALTER TABLE ft_ttd DROP COLUMN rating; -- if you like

    SELECT id,
           num,
           @i := @i + 1 AS rating
      FROM ft_ttd
CROSS JOIN (SELECT @i := 0 AS zero) d
  ORDER BY num DESC;

К сожалению, вы не можете обернуть этот SELECT в VIEW (так как представление «Оператор SELECT не может ссылаться на системные или пользовательские переменные» ).Однако вы можете скрыть это в выбираемой хранимой процедуре:

 CREATE PROCEDURE sp_ranked_ft_ttd () BEGIN
     SELECT id, num, @i := @i + 1 AS rating
       FROM ft_ttd CROSS JOIN (SELECT @i := 0 AS zero) d
   ORDER BY num DESC
 END

Или ОБНОВЛЕНИЕ, если вы должны

В качестве ключа, если вы должны хранить rating в таблице, а не вычислять ее, вы можете запустить это ОБНОВЛЕНИЕ по мере необходимости:

    UPDATE t
CROSS JOIN (    SELECT id, @i := @i + 1 AS new_rating
                  FROM ft_ttd
            CROSS JOIN (SELECT @i := 0 AS zero) d
              ORDER BY num DESC
           ) ranked
        ON ft_ttd.id = ranked.id SET ft_ttd.rating = ranked.new_rating;

Теперь проинструктируйте ваш клиентский код игнорировать строки, где rating IS NULL - они еще не ранжированы.Лучше создайте ВИД, который сделает это за вас.

Продвигаясь дальше, вы, вероятно, можете регулярно ОБНОВЛЯТЬ через СОЗДАТЬ СОБЫТИЕ .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...