在 MySQL 中使用动态 SQL 创建游标

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)


小智 6

创建另一个过程并在此新过程中编写游标代码,然后从您要声明游标的位置调用该过程...

  • 这真的是最好的解决方案吗?好麻烦! (6认同)