我有一个表(ft_ttd),想要按降序排序(num)并将评级数字插入评级栏。
Initial Table http://dl.dropbox.com/u/3922390/2.png
类似的东西:
Result Table 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.
任何想法如何使它工作?也许这个过程可以优化? 谢谢!
答案 0 :(得分:2)
create table语句是一个隐式提交,因为它是DDL。基本上,答案是您无法在触发器中创建表。
http://dev.mysql.com/doc/refman/5.0/en/stored-program-restrictions.html
答案 1 :(得分:1)
其次,你真的想要一个语句级触发器,而不是FOR EACH ROW - 不需要为每个受影响的行重新排列整个表 - 但那是not supported in MySQL 5。
"rating"
那么......只使用MySQL ROW_NUMBER() workaround动态计算rating
吗?
-- 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 statement cannot refer to system or user variables")。但是,您可以在可选择的存储过程中隐藏它:
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
作为一个kluge,如果您必须在表中存储rating
而不是计算它,您可以根据需要运行此UPDATE:
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
- 那些尚未排名的行。更好的是,为你创建一个VIEW。
进一步说,您可以通过CREATE EVENT定期更新。