MySQL 游标(Cursor)是一种数据库对象,用于逐行处理查询结果集。游标允许在存储过程中对查询结果进行逐行操作,这在需要对每一行进行复杂处理时非常有用。
游标的基本概念
声明游标:在存储过程或函数中,游标必须在所有变量声明之后进行声明。游标的声明指定了要执行的查询。
打开游标:在使用游标之前,必须先打开游标。打开游标会执行声明时指定的查询,并将结果集存储在游标中。
获取数据:使用 FETCH 语句从游标中获取一行数据,并将其存储在指定的变量中。
关闭游标:在完成游标的使用后,必须关闭游标以释放资源。
异常处理:通常使用 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 ;
游标声明:游标的声明是在存储过程的开始部分进行的。声明游标时,指定了游标要执行的 SQL 查询。
打开游标:当您打开游标时,游标会执行声明时指定的 SQL 查询,并将结果集存储在游标中。游标的打开操作会根据声明时的查询条件获取数据。
因此,游标的 SQL 查询在每次打开游标时都会被执行一次。这意味着如果您在循环中打开游标,游标的查询会在每次循环中执行,并获取新的数据集。
说明
游标声明:在存储过程的开始部分进行,指定要执行的查询。
异常处理:使用 CONTINUE HANDLER 处理游标结束的情况。
循环处理:使用 LOOP 和 FETCH 逐行处理数据。