Sql 简明教程
SQL - Cursors
数据库光标解决了阻抗不匹配问题。它充当 SQL 查询结果与处理该结果的语句之间的过滤器。
Cursors in SQL
Cursor 是由数据库服务器在对表执行 *D*ata *M*anipulation *L*anguage 操作(如 INSERT、UPDATE 和 DELETE 等)时分配的临时内存。它用来检索和操作存储在 SQL 表中的数据。
使用光标,我们可以对结果集中的每一行执行多个操作,不论是否返回原始数据。
Properties of Cursors
以下是 MySQL 光标的属性 −
-
READ ONLY − 我们无法使用 MySQL 光标更新或修改表中的任何记录。我们只能从表中提取和处理数据。
-
Non-Scrollable − 我们只能单向从表中检索记录,即从第一条记录或最后一条记录开始。我们无法向后移动或跳转到结果集中的特定位置。
-
Asensitive Cursor − 非敏感光标直接对数据库中的实际数据进行操作,它不会创建数据副本。如果其他连接对数据进行了任何更改,它可能会影响光标正在使用的数据。
Declare Cursor Statement
在 MySQL 中,我们可以使用 @{s} 语句声明一个光标并将其与 SELECT 语句关联,以便从数据库表中检索记录。
但是,与游标关联的此 SELECT 语句并不使用 INTO 子句,因为其目的是获取和处理行,而不是将值分配给变量。
Open Cursor Statement
在 MySQL 中声明一个游标后,下一步需要使用 OPEN 语句打开游标。它会初始化 result-set,使我们能够从游标中关联的 SELECT 语句中提取和处理行。
Fetch Cursor Statement
然后,我们可以使用 FETCH 语句来检索游标指向的当前行,并且每次使用 FETCH 时,游标都会移动到 result set 中的下一行。这使我们能够逐个处理各行。
Close Cursor Statement
提取所有行后,我们必须关闭游标以释放与其关联的内存。我们可以使用 CLOSE 语句来执行此操作。
Example
在此示例中,我们了解如何在存储过程中管理游标。
假设我们使用 CREATE TABLE 语句创建了一个名为 CUSTOMERS 的表,如下所示:
CREATE TABLE CUSTOMERS (
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR (25),
SALARY DECIMAL (18, 2),
PRIMARY KEY (ID)
);
现在,我们使用 INSERT 语句向 CUSTOMERS 表中插入一些记录,如下所示:
INSERT INTO CUSTOMERS VALUES
(1, 'Ramesh', 32, 'Ahmedabad', 2000.00 ),
(2, 'Khilan', 25, 'Delhi', 1500.00 ),
(3, 'Kaushik', 23, 'Kota', 2000.00 ),
(4, 'Chaitali', 25, 'Mumbai', 6500.00 );
现在,我们创建一个名为“CUSTOMERS_BACKUP”的备份表来存储客户数据:
CREATE TABLE CUSTOMERS_BACKUP (
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
PRIMARY KEY (ID)
);
在此,我们创建了一个名为 FetchCustomers 的存储过程,用于从 CUSTOMERS 表中提取客户姓名,并将它们逐个插入到 BACKUP 表中。我们使用游标来迭代行,并使用处理程序检测 result-set 的结尾,确保处理所有名称:
DELIMITER //
CREATE PROCEDURE FetchCustomers()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE customer_id INT;
DECLARE customer_name VARCHAR(255);
DECLARE auto_id INT;
-- Declare cursor
DECLARE MY_CURSOR CURSOR FOR
SELECT id, name FROM CUSTOMERS;
-- Declare exit handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Open cursor
OPEN MY_CURSOR;
-- Fetch and insert rows
read_loop: LOOP
FETCH MY_CURSOR INTO customer_id, customer_name;
IF done = 1 THEN
LEAVE read_loop;
END IF;
-- Insert the fetched data into the backup table
INSERT INTO customers_backup VALUES (customer_id, customer_name);
-- Get the last auto-generated ID used in the insertion
SET auto_id = LAST_INSERT_ID();
END LOOP;
-- Close cursor
CLOSE MY_CURSOR;
END //
DELIMITER ;
成功创建过程后,我们可以使用 CALL 语句执行它,如下所示:
CALL FetchCustomers();