好的,我们来系统地讲解 SQL 游标(Cursor),包括概念、使用场景、声明方式以及内部循环使用的完整示例。这里以 SQL Server 为例,也会兼顾 MySQL 和 Oracle 的差异说明。
1️⃣ 游标概念
SQL 是 集合操作语言,擅长批量操作,但有些情况下需要 逐行处理数据。
这时就需要 游标 (Cursor)。
- 游标 是一种指针,用于遍历查询结果集的每一行。
- 适用场景:
- 逐行处理复杂逻辑
- 对结果集的每一行进行计算或条件判断
- 在存储过程或触发器中按行操作数据
⚠️ 游标会占用资源,性能低于批量操作,所以非必要尽量用集合操作替代。
2️⃣ 游标的生命周期
游标的使用通常包括 四个步骤:
- 声明 (DECLARE):定义游标和要遍历的查询。
- 打开 (OPEN):执行查询并准备游标。
- 取值 (FETCH):逐行获取游标中的数据。
- 关闭 (CLOSE) 并释放 (DEALLOCATE):释放资源。
3️⃣ SQL Server 游标示例
-- 示例表
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
Name NVARCHAR(50),
Salary DECIMAL(10,2)
);
INSERT INTO Employees VALUES
(1, 'Alice', 5000),
(2, 'Bob', 6000),
(3, 'Charlie', 5500);
-- 1. 声明游标
DECLARE EmployeeCursor CURSOR FOR
SELECT EmployeeID, Name, Salary
FROM Employees
WHERE Salary < 6000;
-- 2. 打开游标
OPEN EmployeeCursor;
-- 3. 声明变量接收每行数据
DECLARE @EmployeeID INT;
DECLARE @Name NVARCHAR(50);
DECLARE @Salary DECIMAL(10,2);
-- 4. 取值循环
FETCH NEXT FROM EmployeeCursor INTO @EmployeeID, @Name, @Salary;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 示例处理:加薪 10%
UPDATE Employees
SET Salary = Salary * 1.1
WHERE EmployeeID = @EmployeeID;
PRINT 'Updated ' + @Name + ' salary to ' + CAST(@Salary * 1.1 AS NVARCHAR(20));
-- 获取下一行
FETCH NEXT FROM EmployeeCursor INTO @EmployeeID, @Name, @Salary;
END
-- 5. 关闭并释放游标
CLOSE EmployeeCursor;
DEALLOCATE EmployeeCursor;
-- 查看更新结果
SELECT * FROM Employees;
4️⃣ MySQL 游标示例
MySQL 游标通常在 存储过程中使用:
DELIMITER $$
CREATE PROCEDURE UpdateSalaries()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE emp_id INT;
DECLARE emp_name VARCHAR(50);
DECLARE emp_salary DECIMAL(10,2);
DECLARE cur CURSOR FOR
SELECT EmployeeID, Name, Salary FROM Employees WHERE Salary < 6000;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO emp_id, emp_name, emp_salary;
IF done THEN
LEAVE read_loop;
END IF;
-- 示例处理:加薪 10%
UPDATE Employees
SET Salary = Salary * 1.1
WHERE EmployeeID = emp_id;
END LOOP;
CLOSE cur;
END$$
DELIMITER ;
-- 调用存储过程
CALL UpdateSalaries();
-- 查看结果
SELECT * FROM Employees;
5️⃣ 小结
- 游标适合逐行处理而不是批量操作。
- SQL Server 和 MySQL 在语法上略有差异,主要区别:
- SQL Server 使用
WHILE @@FETCH_STATUS = 0
进行循环 - MySQL 使用
LOOP
+CONTINUE HANDLER
控制循环结束
- SQL Server 使用
- 使用完游标必须 关闭并释放,否则会占用资源。
发表回复