Muh*_*mar 9 mysql stored-procedures dynamic-sql cursor
我正在编写一个存储过程,它打开一个指向表的游标,然后遍历所有记录。在迭代过程中,我根据第一个游标的结果创建了一个动态查询。
我需要在动态 SQL 上打开游标,但 MySQL 不允许我这样做。根据 MySQL 的官方文档:“必须在声明处理程序之前声明游标。必须在声明游标或处理程序之前声明变量和条件”。
这是脚本:
DELIMITER $$
DROP PROCEDURE IF EXISTS sp_test$$
CREATE PROCEDURE `sp_test`()
BEGIN
-- Declarations
DECLARE prepared_sql VARCHAR(1000);
DECLARE index_count INT;
-- Cursors
DECLARE cursor1 CURSOR FOR SELECT * from table1;
-- Continue Handler for Cursor
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
-- Open cursors
OPEN cursor1;
-- Business Logic
all_alerts_loop: LOOP
-- Fetch record from cursor1 and create a dynamic sql
-- Check if cursor has reached to end than leave the loop
IF no_more_rows THEN
LEAVE all_alerts_loop;
END IF;
WHILE @some_other_variable <> 0
DO
-- I want to open cursor 2 on this sql
-- set @prepared_sql = 'create dynamic sql here';
END WHILE;
-- This works fine
PREPARE stmt FROM @prepared_sql;
EXECUTE stmt;
-- But can't define cursor here? so what is the solution
-- Gives syntax error, I have tried with @prepared_sql also rather than stmt
DECLARE cursor2 CURSOR FOR stmt;
END LOOP;
-- closing cursors
CLOSE cursor1;
END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)
关于如何为动态查询创建游标的任何想法?在 MySQL 中?
小智 8
不允许使用 DEFINE cur CURSOR FOR Prepared_statement,您必须定义有效的 SQL 语句。好消息是您可以在以后可以动态创建的视图上定义游标。例如...
DROP PROCEDURE IF EXISTS my_dynamic_proc;
DELIMITER //
CREATE PROCEDURE my_dynamic_proc(tablename varchar(64), fieldname varchar(64), country VARCHAR(64))
BEGIN
DECLARE adr_value varchar(500);
DECLARE done BOOLEAN DEFAULT FALSE;
-- Cursor definition
DECLARE cur1 CURSOR FOR SELECT address FROM tmp_view_address;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Dynamic view definition and creation
SET @v = concat('CREATE OR REPLACE VIEW tmp_view_address as SELECT `',fieldname,'` as address FROM ',tablename,' WHERE country_name = "',country,'" group by 1 order by count(1) desc');
PREPARE stm FROM @v;
EXECUTE stm;
DEALLOCATE PREPARE stm;
-- Open cursor
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO adr_value;
IF done THEN
LEAVE read_loop;
END IF;
-- Basic output result
SELECT concat("My address is ",adr_value);
-- Use every result in a dynamic update
SET @u = concat('update ',tablename,' set new_field_address = "',adr_value,'" where country_name = "',country,'" and new_field_address is null');
PREPARE stm FROM @u;
EXECUTE stm;
DEALLOCATE PREPARE stm;
END LOOP;
CLOSE cur1;
END//
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)