行莫
行莫
发布于 2025-06-12 / 15 阅读
0
0

MySQL 游标简单使用示例

MySQL 游标(Cursor)是一种数据库对象,用于逐行处理查询结果集。游标允许在存储过程中对查询结果进行逐行操作,这在需要对每一行进行复杂处理时非常有用。

游标的基本概念

  1. 声明游标:在存储过程或函数中,游标必须在所有变量声明之后进行声明。游标的声明指定了要执行的查询。

  1. 打开游标:在使用游标之前,必须先打开游标。打开游标会执行声明时指定的查询,并将结果集存储在游标中。

  1. 获取数据:使用 FETCH 语句从游标中获取一行数据,并将其存储在指定的变量中。

  1. 关闭游标:在完成游标的使用后,必须关闭游标以释放资源。

  1. 异常处理:通常使用 CONTINUE HANDLER 来处理游标的结束(即没有更多行可获取的情况)。

游标的使用步骤

声明游标:

   DECLARE cursor_name CURSOR FOR
   SELECT column1, column2 FROM table_name WHERE condition;

打开游标:

   OPEN cursor_name;

获取数据:

   FETCH cursor_name INTO variable1, variable2;

关闭游标:

   CLOSE cursor_name;

异常处理:

   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

示例

以下是一个使用游标的简单示例,演示如何在存储过程中使用游标逐行处理数据:

DELIMITER $$

CREATE PROCEDURE ProcessData()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE v_column1 INT;
    DECLARE v_column2 VARCHAR(255);

    -- 声明游标
    DECLARE cur1 CURSOR FOR
    SELECT column1, column2 FROM my_table WHERE some_condition;

    -- 异常处理
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    -- 打开游标
    OPEN cur1;

    -- 读取数据
    read_loop: LOOP
        FETCH cur1 INTO v_column1, v_column2;
        IF done THEN
            LEAVE read_loop;
        END IF;

        -- 在这里处理每一行数据
        -- 例如:UPDATE another_table SET column = v_column1 WHERE column2 = v_column2;
    END LOOP;

    -- 关闭游标
    CLOSE cur1;
END$$

DELIMITER ;

循环中使用游标的简单示例:

DELIMITER $$
CREATE PROCEDURE deleteProcedure()
BEGIN
    -- 变量声明
    DECLARE done INT DEFAULT FALSE;
    DECLARE batch_size INT DEFAULT 5000;
    DECLARE start_id INT DEFAULT 0;
    DECLARE max_id INT;
    DECLARE v_id INT;
    DECLARE v_product_id BIGINT;
    -- 游标声明
    DECLARE cur1 CURSOR FOR
        SELECT id, product_id FROM table_1
        WHERE id > start_id AND id <= start_id + batch_size;
    -- 异常处理
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    -- 获取表中最大 id
    SELECT MAX(id) INTO max_id FROM table_1;
    -- 创建临时表
    CREATE TEMPORARY TABLE IF NOT EXISTS temp_ids (
                                                      id INT,
                                                      product_id BIGINT
    );
    -- 外层循环控制批次
    WHILE start_id <= max_id DO
            -- 清空临时表
            TRUNCATE TABLE temp_ids;
            -- 打开游标
            OPEN cur1;
            read_loop: LOOP
                FETCH cur1 INTO v_id, v_product_id;
                IF done THEN
                    LEAVE read_loop;
                END IF;
                -- 将数据插入临时表
                INSERT INTO temp_ids (id, product_id) VALUES (v_id, v_product_id);
            END LOOP;
            -- 关闭游标
            CLOSE cur1;
            -- 执行批量删除操作
            DELETE FROM table_2 WHERE parent_sku_id IN (SELECT product_id FROM temp_ids);  
            -- 清除 done 标志以便下一轮使用
            SET done = FALSE;
            -- 更新起始 id
            SET start_id = start_id + batch_size;
        END WHILE;
    -- 删除临时表
    DROP TEMPORARY TABLE IF EXISTS temp_ids;
END$$
DELIMITER ;
  1. 游标声明:游标的声明是在存储过程的开始部分进行的。声明游标时,指定了游标要执行的 SQL 查询。

  1. 打开游标:当您打开游标时,游标会执行声明时指定的 SQL 查询,并将结果集存储在游标中。游标的打开操作会根据声明时的查询条件获取数据。

因此,游标的 SQL 查询在每次打开游标时都会被执行一次。这意味着如果您在循环中打开游标,游标的查询会在每次循环中执行,并获取新的数据集。

说明

  • 游标声明:在存储过程的开始部分进行,指定要执行的查询。

  • 异常处理:使用 CONTINUE HANDLER 处理游标结束的情况。

  • 循环处理:使用 LOOPFETCH 逐行处理数据。


评论