【问题标题】:Call a stored procedure for each row returned by a query in MySQL为 MySQL 中查询返回的每一行调用一个存储过程
【发布时间】:2018-08-13 01:44:44
【问题描述】:

我想要一个有效的 MySQL 存储过程:

foreach id in (SELECT id FROM objects WHERE ... ) CALL testProc(id)

我想我只是想要这个问题的 MySQL 答案,但我不太了解游标:How do I execute a stored procedure once for each row returned by query?

【问题讨论】:

    标签: mysql stored-procedures


    【解决方案1】:

    “循环”(for-each、while 等)和“分支”(if-else、调用等)等概念是过程性的,不存在于声明性 语言,如 SQL。通常人们可以用声明的方式表达自己想要的结果,这将是解决这个问题的正确方法。

    例如,如果要调用的 testProc 过程使用给定的 id 作为另一个表的查找键,那么您可以(并且应该)简单地将 JOIN 放在一起 - 例如:

    SELECT ...
    FROM   objects JOIN other USING (id)
    WHERE  ...
    

    只有在极少数情况下您的问题无法以声明方式表达时,您才应该诉诸程序解决问题。存储过程是在 MySQL 中执行过程代码的唯一方法。因此,您要么需要修改现有的 sproc,使其在循环中执行其当前逻辑,要么创建一个新的 sproc,从循环中调用现有的:

    CREATE PROCEDURE foo() BEGIN
      DECLARE done BOOLEAN DEFAULT FALSE;
      DECLARE _id BIGINT UNSIGNED;
      DECLARE cur CURSOR FOR SELECT id FROM objects WHERE ...;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
    
      OPEN cur;
    
      testLoop: LOOP
        FETCH cur INTO _id;
        IF done THEN
          LEAVE testLoop;
        END IF;
        CALL testProc(_id);
      END LOOP testLoop;
    
      CLOSE cur;
    END
    

    【讨论】:

    • 这种手动设置变量终止“循环”的模式,这是正常的方式吗?看起来很笨重!
    • @John:是的。尽管为表中的每条记录调用过程的模式不太正常(至少可以迭代 testProc 内的游标,但即使这样也可能是不必要的:testProc 做了什么?)。
    • 这是一个游戏,当游戏结束时,它必须更新与每个玩家相关的几个表......所以在你的例子中 foo() 正在迭代链接到单个游戏的每个玩家,并且 @ 987654329@ 为单个玩家做了很多事情。数据库中的应用逻辑比其他任何东西都重要。
    • 请记住,如果您有更多选择,例如。之前和之后的产品价格,您需要创建更多(_price,_newPrice)才能获取 _price 和 _newPrice。非常感谢这篇简单的帖子。
    • 语法错误:DECLARE done BOOLEAN DEFAULT FALSE; 后缺少半列
    猜你喜欢
    • 1970-01-01
    • 2020-05-01
    • 2017-03-28
    • 2012-04-01
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多