版权声明
- 本文原创作者:清风不渡
- 博客地址:https://blog.csdn.net/WXKKang
引言
1、什么是结果集?
游标作为一个处理结果集的方法,想要学习游标,我们就首先应该了解什么叫做结果集,那么,什么是结果集呢?从字面意思上来看,结果集就是当我们执行一个查询之后,数据库给我们返回的所有符合条件的结果数据的一个集合(满足SELECT语句的WHERE子句中条件的所有行),这种由语句返回的完整行集称为结果集。
2、为什么需要使用游标?
我们既然要学习游标,那么最应该知道的就是我们为什么需要使用游标?
执行查询语句后获得的结果集,就像是我们获得了一块完整的大蛋糕,我们只能对它全部作以处理,或是一口全部吃掉或是全部扔掉,假如我们想要对它的某一部分进行处理(例如这一部分有奶油的送给小王吃,那一部分有水果的送给小李吃),就会显得力不从心,那么我们就需要一种方法,对结果集的某一部分或是各个部分进行不同的处理,这个方法就是使用游标
一、游标
1、基本概念
游标(Cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行或者多行前进或向后浏览数据的能力,它可以定位到结果集中的某一行,可以让用户对当前位置的数据进行读写,利用它我们可以对结果集中的数据进行单独操作。
我们可以把它当作一个指针,它可以指定结果中的任何位置,然后允许用户对指定位置的数据进行处理
游标可以为由其他用户对显示在结果集中的数据库数据所做的更改提供不同级别的可见性支持
我们可以在脚本、存储过程和触发器中编写游标用于访问结果集中的数据的Transact-SQL语句
通过游标我们可以循环的去处理数据,而游标又分为静态游标和动态游标,静态游标中的数据是固定的,不会因为原数据表的数据改变而改变,动态游标则相反,游标默认是动态游标,通过关键字STATIC我们就可以设置游标为静态游标或是动态游标
2、游标的实现步骤
游标的实现主要分为以下四个步骤:
第一步:声明游标
第二步:打开游标
第三步:提取游标
第四步:释放游标
-- 声明变量
DECLARE [变量名] [变量类型]
-- 声明游标
DECLARE [游标名] CURSOR FOR [结果集]
-- 打开游标
OPEN [游标名]
-- 循环游标
FETCH NEXT FROM [游标名] INTO [变量名]
WHILE @@FETCH_STATUS = 0
BEGIN
-- 业务数据处理代码
---
---
FETCH NEXT FROM [游标名] INTO [变量名]
END
-- 关闭游标
CLOSE [游标名]
-- 释放游标
DEALLOCATE [游标名]
3、游标示例
现在我们就通过一个例子来学习游标,测试数据如下:
CREATE TABLE [dbo].[student](
[student_id] [varchar](50) NOT NULL PRIMARY KEY,
[student_name] [varchar](50) NULL
)
GO
INSERT INTO STUDENT VALUES
('S001','Jack'),
('S002','Jane'),
('S003','张三')
GO
CREATE TABLE [dbo].[student_copy](
[student_id] [varchar](50) NOT NULL PRIMARY KEY,
[student_name] [varchar](50) NULL
)
GO
下面我们来通过存储过程实现数据的拷贝,调用存储过程时需输入学生ID,存储过程中通过游标的形式遍历数据表,当找到匹配的数据时将整条数据拷贝到数据表student_copy中,如果没有找到匹配的数据则提示学生ID无效,代码如下:
USE [demo]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[test_procedure]
@STUDENT_ID VARCHAR(50)
AS
BEGIN
DECLARE @ID VARCHAR(50),@NAME VARCHAR(50),@I INT
SET @I = 0
-- 声明游标
DECLARE MyCursor CURSOR FOR SELECT STUDENT_ID FROM STUDENT
-- 打开游标
OPEN MyCursor
-- 循环游标
FETCH NEXT FROM MyCursor INTO @ID
WHILE @@FETCH_STATUS = 0
BEGIN
IF @ID = @STUDENT_ID
BEGIN
IF EXISTS (SELECT 1 FROM STUDENT_COPY WHERE STUDENT_ID = @ID)
BEGIN
RAISERROR('STUDENT_COPY表中已存在该学生数据,无需拷贝',1,16)
END
ELSE
BEGIN
INSERT INTO STUDENT_COPY
SELECT STUDENT_ID,STUDENT_NAME FROM STUDENT WHERE STUDENT_ID = @ID
PRINT '数据拷贝完成'
SET @I = 1
END
END
FETCH NEXT FROM MyCursor INTO @ID
END
-- 关闭游标
CLOSE MyCursor
-- 释放游标
DEALLOCATE MyCursor
IF @I = 0
BEGIN
RAISERROR('学生ID无效,请重新输入',1,16)
END
END
下面我们对上面的存储过程进行测试:
(1)当输入的学生ID不存在时:
exec test_procedure ‘S005’
(2)当输入的学生ID存在于student表中时:
exec test_procedure ‘S001’
检查student_copy表中数据:
SELECT * FROM STUDENT_copy
(3)当输入学生ID重复时:
exec test_procedure ‘S001’
当然,上面这个例子也可以通过普通的T-SQL代码来实现,这样只不过是一种方法而已,而且数据量一但过大也会导致执行时间过长,只是为了体现它的执行过程而已,咱们下篇再见 ~ ~