我在MySQL中有这个程序(不用弄清楚它的功能,只需看看光标打开的部分)
/* PROCEDURE 1 : Post notification */
DROP PROCEDURE IF EXISTS AddNotificationOnPosts;
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `AddNotificationOnPosts`(arg_from_user INT(11),arg_on_post_id INT(11),arg_in_group_id INT(11))
BEGIN
DECLARE num_rows INT DEFAULT NULL;
DECLARE insert_result INT DEFAULT NULL;
DECLARE done INT DEFAULT 0;
DECLARE var_user_id INT DEFAULT NULL;
DECLARE c1 CURSOR FOR
SELECT user_id
FROM user_rights
WHERE user_rights.right = 101 AND user_rights.group_id = arg_in_group_id
ORDER BY user_id DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
IF(arg_from_user IS NULL OR arg_from_user = '')
THEN
SELECT "0" AS response;
ELSEIF(arg_on_post_id IS NULL OR arg_on_post_id = '')
THEN
SELECT "0" AS response;
ELSEIF(arg_in_group_id IS NULL OR arg_in_group_id = '')
THEN
SELECT "0" AS response;
ELSE
SELECT count(notification_id) FROM notifications_posts
WHERE
from_user = arg_from_user AND
on_post_id = arg_on_post_id AND
in_group_id = arg_in_group_id
INTO num_rows;
END IF;
IF num_rows = 0
THEN
INSERT INTO notifications_posts(from_user,on_post_id,in_group_id) VALUES(arg_from_user,arg_on_post_id,arg_in_group_id);
SELECT ROW_COUNT() INTO insert_result;
IF insert_result > 0
THEN
/* Increment the notifications for every user*/
OPEN c1;
read_loop: LOOP
FETCH c1 INTO var_user_id;
IF done THEN
LEAVE read_loop;
ELSE
IF NOT(var_user_id = arg_from_user)
THEN
/* UPDATING */
UPDATE user_info SET notifications = notifications + 1 WHERE user_info.user_id = var_user_id;
/* SELECTING RESULT */
SELECT
user_info.user_id,
messages,
tasks,
notifications,
messages+tasks+notifications AS total
FROM user_rights
INNER
JOIN user_info
ON user_info.user_id = user_rights.user_id
WHERE user_rights.right = 101 AND user_rights.group_id = arg_in_group_id ;
END IF;
END IF;
END LOOP;
CLOSE c1;
ELSE
SELECT "0" AS response;
END IF;
ELSE
SELECT "0" AS response;
END IF;
END $$
DELIMITER ;
并在此部分
/* Increment the notifications for every user*/
OPEN c1;
read_loop: LOOP
FETCH c1 INTO var_user_id;
IF done THEN
LEAVE read_loop;
ELSE
IF NOT(var_user_id = arg_from_user)
THEN
/* UPDATING */
UPDATE user_info SET notifications = notifications + 1 WHERE user_info.user_id = var_user_id;
/* SELECTING RESULT */
SELECT
user_info.user_id,
messages,
tasks,
notifications,
messages+tasks+notifications AS total
FROM user_rights
INNER
JOIN user_info
ON user_info.user_id = user_rights.user_id
WHERE user_rights.right = 101 AND user_rights.group_id = arg_in_group_id ;
END IF;
END IF;
END LOOP;
CLOSE c1;
程序选择数据,然后更新它(相信我,我已经死了),我真的需要选择之后,因为我生成了XML
的数据,这样:
1为什么选择然后更新,因为我看到select位于更新
下面2谁有这个"出色的想法"这样做?
谢谢。
答案 0 :(得分:1)
当您在sql-server中进行一次批量更新/删除和其他操作时,完全不确定将执行“命令”的顺序。 这个问题的解决方案是使用“exec”语句将“update”放在不同的批处理中。所以尝试使用:
exec('UPDATE user_info SET notifications = notifications + 1 WHERE user_info.user_id =' + var_user_id);
现在应该可以了。
答案 1 :(得分:1)
我解决了问题:SELECT
语句必须在CURSOR LOOP
之外。
答案 2 :(得分:0)
我认为更新和选择是按照正确的顺序执行的,但是选择不能"参见"由于事务隔离而导致的更新结果。
我建议使用以下解决方案来解决此问题并通过消除后续选择中的连接来提高性能:
set @notification = 0;
/* UPDATING */
UPDATE user_info SET notifications = @notification := notifications + 1 WHERE user_info.user_id = var_user_id;
/* SELECTING RESULT */
SELECT
user_info.user_id,
messages,
tasks,
notifications,
messages+tasks+@notifications AS total
FROM user_rights
WHERE user_rights.right = 101 AND user_rights.group_id = arg_in_group_id ;