首页 > 解决方案 > 当我们需要在 SQL 中使用无法通过基于集合的方法解决的游标时的示例

问题描述

有人可以举例说明我们何时需要在 SQL 中使用无法通过基于集合的方法解决的游标。

谢谢

标签: sqlsql-servertsql

解决方案


当您需要逐行执行操作时,通常会使用游标。这是我们经常将其转移到 DBMS 之外的其他工具的东西。一般来说,DBMS 的优势在于基于集合的数据方法。但是..举个例子。

假设您有一个表,其他进程在其中写入要存储并在以后发送的邮件消息。可能有多个 SQL 作业在运行并且每个都写入自己的状态,那么当第二天早上到来或服务器负载非常低时,DBMS 会自行发送这些。

使用一些数据设置示例表:

CREATE TABLE outgoingMessages
(
    recipient VARCHAR(MAX),
    subject NVARCHAR(255),
    message NVARCHAR(MAX)
)

INSERT INTO dbo.outgoingMessages (recipient,subject,message)
VALUES
('foo@bar.com', N'An email', N'Procedure dbo.Foo ran with statuscode X'),
('foo@bar.com', N'An email', N'Procedure dbo.Bar ran with statuscode Y'),
('manager@bar.com', N'An email', N'Data synchronisation had problems, ask foo')

然后作为理论上的结束步骤/结束工作,我们有一个处理表格并处理所有构建消息的过程。

/* Scheduled job */ 
DECLARE mailCursor CURSOR FOR 
SELECT * FROM dbo.outgoingMessages;

DECLARE @mailRecipient VARCHAR(MAX); 
DECLARE @mailSubject NVARCHAR(255); 
DECLARE @mailMessage NVARCHAR(MAX);

OPEN mailCursor;

FETCH NEXT FROM mailCursor INTO 
@mailRecipient, @mailSubject, @mailMessage 

WHILE @@FETCH_STATUS = 0
BEGIN
  PRINT @mailRecipient + ' ' + @mailSubject + ' ' + @mailMessage

  EXEC msdb.dbo.sp_send_dbmail 
  @profile_name = N'defaultMailprofile',
  @recipients = @mailRecipient,
  @subject = @mailSubject,
  @body = @mailMessage


  FETCH NEXT FROM mailCursor INTO 
  @mailRecipient, @mailSubject, @mailMessage

END

CLOSE mailCursor; 
DEALLOCATE mailCursor;

这使得数据库单独打印出所有行,并将邮件发送到表中每一行的指定变量(为其调用另一个存储过程)。我想说这行操作,为每一行获取数据并进一步操作它或将其用作另一个过程的变量是一个更常见的用例。

/* Print results */
foo@bar.com An email Procedure dbo.Foo ran with statuscode X
foo@bar.com An email Procedure dbo.Bar ran with statuscode Y
manager@bar.com An email Data synchronisation had problems, ask foo

您可以想象一个表,其中可能包含由其他自动化进程构建的 API 调用,然后在以后执行。

游标很常见吗?不,您应该始终考虑他们的用例,并最好使用不同的方法。但是如果你需要为每一行做一些事情,并且可能会根据条件向后跳转。游标允许您在 DBMS 中执行此操作,它们是一个强大的工具。


推荐阅读