SQL Server 中的游标

2025年3月17日 | 阅读 7 分钟

SQL Server 中的游标是一个数据库对象,它允许我们一次检索一行并操作其数据。游标不过是行的一个指针。它总是与 SELECT 语句一起使用。它通常是一组 SQL 逻辑,逐行循环遍历预定的行数。游标的一个简单示例是,当我们拥有大量的员工记录数据库并希望在扣除税费和假期后计算每位员工的工资时。

SQL Server 游标的目的是逐行更新数据、更改数据或执行在一次检索所有记录时不可能完成的计算。它对于执行诸如按顺序备份 SQL Server 数据库之类的管理任务也很有用。游标主要用于开发、DBA 和 ETL 流程。

本文解释了 SQL Server 游标的所有内容,包括游标的生命周期、游标的使用原因和时间、如何实现游标、其限制以及如何替换游标。

游标的生命周期

我们可以将游标的生命周期分为五个不同的部分,如下所示:

Cursor in SQL Server

1:声明游标

第一步是使用以下 SQL 语句声明游标:

我们可以通过在 DECLARE 关键字后指定游标名称及其数据类型 CURSOR 来声明游标。然后,我们将编写定义游标输出的 SELECT 语句。

2:打开游标

这是第二步,我们打开游标以存储从结果集中检索到的数据。我们可以使用以下 SQL 语句完成此操作:

3:提取游标

这是第三步,可以逐行或批量提取行,以对游标中当前活动行执行数据操作,例如插入、更新和删除操作。我们可以使用以下 SQL 语句完成此操作:

我们还可以使用 SQL Server 中的 @@FETCHSTATUS 函数来获取最近针对游标执行的 FETCH 语句的状态。当 @@FETCHSTATUS 返回零输出时,FETCH 语句成功。WHILE 语句可用于从游标中检索所有记录。以下代码更清楚地解释了这一点:

4:关闭游标

这是第四步,在我们完成游标工作后应关闭游标。我们可以使用以下 SQL 语句完成此操作:

5:取消分配游标

这是第五步,也是最后一步,我们将删除游标定义并释放与游标关联的所有系统资源。我们可以使用以下 SQL 语句完成此操作:

SQL Server 游标的用途

我们知道,包括 SQL Server 在内的关系数据库管理系统在处理称为结果集的一组行数据方面非常出色。例如,我们有一个名为 product_table 的表,其中包含产品描述。如果我们要更新产品的价格,那么下面的 'UPDATE' 查询将更新 'WHERE' 子句中满足条件的所有记录:

有时应用程序需要以单行方式处理行,即一次处理一行,而不是一次处理整个结果集。我们可以使用 SQL Server 中的游标来完成此过程。在使用游标之前,我们必须知道游标的性能非常差,因此应始终仅在没有其他选择时才使用游标。

游标使用与我们在所有编程语言中使用的循环(如 FOREACH、FOR、WHILE、DO WHILE)相同的技术来一次迭代一个对象。因此,可以选择它,因为它应用了与编程语言的循环过程相同的逻辑。

SQL Server 中的游标类型

以下是 SQL Server 中不同类型的游标,如下所示:

  • 静态游标
  • 动态游标
  • 前进游标
  • 键集游标
Cursor in SQL Server

静态游标

静态游标显示的结果集与游标首次打开时相同。由于静态游标会将结果存储在 tempdb 中,因此它们始终是只读的。我们可以使用静态游标向前和向后滚动。与其他游标相比,它速度较慢,消耗的内存也更多。因此,我们只能在需要滚动且其他游标不适用时使用它。

此游标显示在打开后已从数据库中删除的行。静态游标不反映任何 INSERT、UPDATE 或 DELETE 操作(除非关闭并重新打开游标)。

动态游标

动态游标与静态游标相反,它允许我们在游标打开时执行数据更新、删除和插入操作。它默认是可滚动的。它可以检测结果集中行的所有更改,无论是行的顺序还是值,无论是发生在游标内部还是外部。在游标外部,我们看不到更新,直到它们被提交。

前进游标

它是所有游标中默认且最快的游标类型。它被称为前进游标,因为它仅向前移动结果集。此游标不支持滚动。它只能从结果集的开头检索到结尾。它允许我们执行插入、更新和删除操作。在这里,用户进行的插入、更新和删除操作影响结果集中行的效果,就像行从游标中提取一样。当行被提取时,我们无法看到通过游标对行所做的更改。

前进游标分为三类:

  1. Forward_Only Keyset
  2. Forward_Only Static
  3. Fast_Forward
Cursor in SQL Server

键集驱动的游标

就检测更改的能力而言,此游标功能介于静态游标和动态游标之间。它不像静态游标那样始终能检测到结果集成员资格和顺序的更改。它像动态游标一样可以检测结果集行值的更改。它只能从第一行移动到最后一行,从最后一行移动到第一行。每当打开此游标时,顺序和成员资格都会固定。

它由一组唯一的标识符操作,与键集中的键相同。键集由游标首次打开时满足 SELECT 语句的所有行确定。它还可以检测数据源的任何更改,这支持更新和删除操作。它默认是可滚动的。

实现示例

让我们在 SQL Server 中实现游标示例。我们可以通过首先使用以下语句创建一个名为 "customer" 的表来完成此操作:

接下来,我们将向表中插入值。我们可以执行以下语句将数据添加到表中:

我们可以通过执行 SELECT 语句来验证数据:

执行查询后,我们可以看到下面的输出,其中表中有八行

Cursor in SQL Server

现在,我们将创建一个游标来显示客户记录。下面的代码片段解释了游标声明或创建的所有步骤,将所有内容整合在一起:

执行游标后,我们将获得以下输出:

Cursor in SQL Server

SQL Server 游标的限制

游标有一些限制,因此应始终仅在没有其他选择时才使用游标。这些限制是:

  • 游标会消耗网络资源,每次提取记录都需要网络往返。
  • 游标是内存驻留的指针集,这意味着它会占用一些其他进程可以在我们的机器上使用的内存。
  • 在处理数据时,它会对表的一部分或整个表施加锁。
  • 游标的性能和速度较慢,因为它们一次更新表记录一行。
  • 游标比 while 循环快,但它们有更多的开销。
  • 提取到游标中的行数和列数是影响游标速度的另一个方面。它指的是打开游标和执行 fetch 语句所需的时间。

如何避免游标?

游标的主要工作是逐行遍历表。避免游标的最简单方法如下:

使用 SQL while 循环

避免使用游标的最简单方法是使用 while 循环,该循环允许将结果集插入临时表中。

用户定义函数

有时使用游标来计算结果行集。我们可以通过使用满足要求的用户定义函数来实现这一点。

使用 JOIN

JOIN 只处理满足指定条件的列,从而减少了代码行数,在需要处理大量记录的情况下,其性能比游标更快。