在 MySQL 中使用游标时从 DECLARE 语句调用存储过程
Call a stored procedure from the DECLARE statement when using cursors in MySQL
我试图在 MySQL 中使用游标多次调用存储过程。我想多次调用它,因为 my_id
的值存在于某个临时 table 中,并遍历这些 ID 并连接结果。
无论如何,我在这部分过程中遇到了问题:
DECLARE curs CURSOR FOR
SELECT something FROM somewhere;
我不想 select 从某个地方得到一些东西。我想要类似
的东西
DECLARE curs CURSOR FOR
CALL storedproc(@an_id);
DECLARE
语句可以用来调用存储过程吗?或者它是否必须仅与 SELECT
相关联? google了一下,恐怕是后者吧
Can the DECLARE statement be used to call a stored proc?
不可能,文档对此非常清楚
Cursor DECLARE Syntax
This statement declares a cursor and associates it with a SELECT statement that retrieves the rows to be traversed by the cursor. To fetch the rows later, use a FETCH statement. The number of columns retrieved by the SELECT statement must match the number of output variables specified in the FETCH statement.
使用游标需要一些标准的样板代码来包围它。
使用游标为 table 中的每组值调用存储过程需要基本相同的样板。您 SELECT
您想要传递的值,无论您从何处获取它们(可以是临时 table、基础 table 或视图,并且可以包括对存储函数的调用)然后使用这些值调用过程。
我在下面编写了该样板代码的语法有效示例,并附有注释以解释每个组件的作用。没有什么比被要求做某事更让我不喜欢的了 "just because" -- 所以一切都(希望)得到了解释。
您提到调用具有多个值的过程,因此此示例使用 2。
请注意,由于某种原因,她发生的事件按特定顺序排列。变量必须首先声明,游标必须在它们的继续处理程序之前声明,循环必须遵循所有这些事情。这给人的印象是这里有一些相当极端的僵化,但事实并非如此。您可以通过在过程主体内的 BEGIN
... END
块内嵌套附加代码来重置顺序;例如,如果在循环内需要第二个游标,只需在循环内声明它,在另一个 BEGIN
... END
内。
DELIMITER $$
DROP PROCEDURE IF EXISTS `my_proc` $$
CREATE PROCEDURE `my_proc`(arg1 INT) -- 1 input argument; you might not need one
BEGIN
-- from
-- declare the program variables where we'll hold the values we're sending into the procedure;
-- declare as many of them as there are input arguments to the second procedure,
-- with appropriate data types.
DECLARE val1 INT DEFAULT NULL;
DECLARE val2 INT DEFAULT NULL;
-- we need a boolean variable to tell us when the cursor is out of data
DECLARE done TINYINT DEFAULT FALSE;
-- declare a cursor to select the desired columns from the desired source table1
-- the input argument (which you might or might not need) is used in this example for row selection
DECLARE cursor1 -- cursor1 is an arbitrary label, an identifier for the cursor
CURSOR FOR
SELECT t1.c1,
t1.c2
FROM table1 t1
WHERE c3 = arg1;
-- this fancy spacing is of course not required; all of this could go on the same line.
-- a cursor that runs out of data throws an exception; we need to catch this.
-- when the NOT FOUND condition fires, "done" -- which defaults to FALSE -- will be set to true,
-- and since this is a CONTINUE handler, execution continues with the next statement.
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- open the cursor
OPEN cursor1;
my_loop: -- loops have to have an arbitrary label; it's used to leave the loop
LOOP
-- read the values from the next row that is available in the cursor
FETCH NEXT FROM cursor1 INTO val1, val2;
IF done THEN -- this will be true when we are out of rows to read, so we go to the statement after END LOOP.
LEAVE my_loop;
ELSE -- val1 and val2 will be the next values from c1 and c2 in table t1,
-- so now we call the procedure with them for this "row"
CALL the_other_procedure(val1,val2);
-- maybe do more stuff here
END IF;
END LOOP;
-- execution continues here when LEAVE my_loop is encountered;
-- you might have more things you want to do here
END $$
DELIMITER ;
我试图在 MySQL 中使用游标多次调用存储过程。我想多次调用它,因为 my_id
的值存在于某个临时 table 中,并遍历这些 ID 并连接结果。
无论如何,我在这部分过程中遇到了问题:
DECLARE curs CURSOR FOR
SELECT something FROM somewhere;
我不想 select 从某个地方得到一些东西。我想要类似
的东西DECLARE curs CURSOR FOR
CALL storedproc(@an_id);
DECLARE
语句可以用来调用存储过程吗?或者它是否必须仅与 SELECT
相关联? google了一下,恐怕是后者吧
Can the DECLARE statement be used to call a stored proc?
不可能,文档对此非常清楚
Cursor DECLARE Syntax
This statement declares a cursor and associates it with a SELECT statement that retrieves the rows to be traversed by the cursor. To fetch the rows later, use a FETCH statement. The number of columns retrieved by the SELECT statement must match the number of output variables specified in the FETCH statement.
使用游标需要一些标准的样板代码来包围它。
使用游标为 table 中的每组值调用存储过程需要基本相同的样板。您 SELECT
您想要传递的值,无论您从何处获取它们(可以是临时 table、基础 table 或视图,并且可以包括对存储函数的调用)然后使用这些值调用过程。
我在下面编写了该样板代码的语法有效示例,并附有注释以解释每个组件的作用。没有什么比被要求做某事更让我不喜欢的了 "just because" -- 所以一切都(希望)得到了解释。
您提到调用具有多个值的过程,因此此示例使用 2。
请注意,由于某种原因,她发生的事件按特定顺序排列。变量必须首先声明,游标必须在它们的继续处理程序之前声明,循环必须遵循所有这些事情。这给人的印象是这里有一些相当极端的僵化,但事实并非如此。您可以通过在过程主体内的 BEGIN
... END
块内嵌套附加代码来重置顺序;例如,如果在循环内需要第二个游标,只需在循环内声明它,在另一个 BEGIN
... END
内。
DELIMITER $$
DROP PROCEDURE IF EXISTS `my_proc` $$
CREATE PROCEDURE `my_proc`(arg1 INT) -- 1 input argument; you might not need one
BEGIN
-- from
-- declare the program variables where we'll hold the values we're sending into the procedure;
-- declare as many of them as there are input arguments to the second procedure,
-- with appropriate data types.
DECLARE val1 INT DEFAULT NULL;
DECLARE val2 INT DEFAULT NULL;
-- we need a boolean variable to tell us when the cursor is out of data
DECLARE done TINYINT DEFAULT FALSE;
-- declare a cursor to select the desired columns from the desired source table1
-- the input argument (which you might or might not need) is used in this example for row selection
DECLARE cursor1 -- cursor1 is an arbitrary label, an identifier for the cursor
CURSOR FOR
SELECT t1.c1,
t1.c2
FROM table1 t1
WHERE c3 = arg1;
-- this fancy spacing is of course not required; all of this could go on the same line.
-- a cursor that runs out of data throws an exception; we need to catch this.
-- when the NOT FOUND condition fires, "done" -- which defaults to FALSE -- will be set to true,
-- and since this is a CONTINUE handler, execution continues with the next statement.
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- open the cursor
OPEN cursor1;
my_loop: -- loops have to have an arbitrary label; it's used to leave the loop
LOOP
-- read the values from the next row that is available in the cursor
FETCH NEXT FROM cursor1 INTO val1, val2;
IF done THEN -- this will be true when we are out of rows to read, so we go to the statement after END LOOP.
LEAVE my_loop;
ELSE -- val1 and val2 will be the next values from c1 and c2 in table t1,
-- so now we call the procedure with them for this "row"
CALL the_other_procedure(val1,val2);
-- maybe do more stuff here
END IF;
END LOOP;
-- execution continues here when LEAVE my_loop is encountered;
-- you might have more things you want to do here
END $$
DELIMITER ;