MySql过程产生错误的结果

时间:2013-06-26 08:02:01

标签: mysql sql stored-procedures

昨天我发现了一件非常有趣(而且意想不到的)的事情。我被赋予了一个任务(在生产环境中)来更新TableA的三列(由于某些明显的原因,我正在改变表和列名),通过获取dummytable中存在的所有值。这两个表的主键是A列。我知道这个任务很简单,可以通过多种方式完成,但我选择为此编写一个存储过程(如下所示)。

当存储过程完成执行时,则注意到列B,C& statusCode具有相同的值(即,数千个记录在这三列中具有相同的值)。谁能告诉我出了什么问题?

1)此存储过程中有什么问题(或缺失)? (虚拟表也有数千条记录) 2)除了创建存储过程之外,还有什么可能是完成此任务的最佳方法?

PS:我使用MySQL工作台在生产环境中创建(执行了)这个存储过程,并且在执行过程中遇到了一个异常,它说明了“与MySQL服务器的连接丢失”,但我猜我自己运行了程序执行时,远程计算机上的程序没有中断服务器。

这是我的存储过程。

DELIMITER $$

CREATE DEFINER=`ABC`@`%` PROCEDURE `RetrieveExtractionData`()

BEGIN

DECLARE claimlisttraversed BOOLEAN DEFAULT FALSE;

DECLARE a VARCHAR(20);

DECLARE b INTEGER;

DECLARE c INTEGER;


DECLARE claimlist CURSOR FOR SELECT
`dummytable`.`A`,
`dummytable`.`B`,
`dummytable`.`C`
FROM `ABC`.`dummytable`;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET claimlisttraversed = TRUE;


OPEN claimlist;

claimlistloop: LOOP

    FETCH claimlist INTO a, b, c;

    IF claimlisttraversed THEN
        CLOSE claimlist;
        LEAVE claimlistloop;
    END IF;
    UPDATE `ABC`.`TableA`
SET
`B` = b,
`C` = c,
`statuscode` = 'Sent'
WHERE `A` = a;

END LOOP claimlistloop;

END

3 个答案:

答案 0 :(得分:1)

关于你的第一个问题:

  

1)此存储过程中有什么问题(或缺失)? (假表有   成千上万的记录)

我猜您忘了CLOSE CURSOR。在您结束LOOP之后,您应该CLOSE CURSOR

END LOOP claimlistloop;

CLOSE claimlist;

END
  

2)除了以外,有什么可能是完成这项任务的最佳方式   创建存储过程?

STORED PROCEDURE中执行此操作应该没问题。并且使用CURSOR也没关系,因为你只需要执行一次程序(我猜因为这是一个生产修正)。

但是,根据您的问题,您只想根据提供的TableA更新DummyTable。我假设这些表具有相同的列。

所以我认为此查询优于CURSOR

UPDATE TableA A
    INNER JOIN DummyTable D ON D.A = A.A
    SET A.B = D.B
        , A.C = D.C
        , A.statuscode = 'Sent';

但请先在备份或虚拟桌面上尝试。我还没有测试过它。

答案 1 :(得分:1)

忘记光标。事实上,如果可以避免,你永远不应该使用游标。游标非常慢。

简单地做

UPDATE 
yourTable yt
INNER JOIN dummyTable dt ON yt.A = dt.A
SET
yt.B = dt.B,
yt.C = dt.C;

你没事。

答案 2 :(得分:1)

  

1)此存储过程中有什么问题(或缺失)? (假表   也有成千上万的记录)
  2)什么是最好的   除了创建存储过程之外,还可以执行此任务吗?

恕我直言,你目前所缺少的最重要的事情是你不需要任何游标。您的整个存储过程是一个UPDATE语句。单独执行或将其包装在存储过程中

CREATE PROCEDURE RetrieveExtractionData()
UPDATE TableA a JOIN dummytable d
    ON a.a = d.a
   SET a.b = d.b, a.c = d.c, a.statuscode = 'Sent'; 

您甚至不需要更改分隔符并使用BEGIN ... END阻止

这是 SQLFiddle 演示。