Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在存储过程中“迭代”SQL结果,但避免使用游标?_Sql_Sql Server_Sql Server 2008_Stored Procedures - Fatal编程技术网

如何在存储过程中“迭代”SQL结果,但避免使用游标?

如何在存储过程中“迭代”SQL结果,但避免使用游标?,sql,sql-server,sql-server-2008,stored-procedures,Sql,Sql Server,Sql Server 2008,Stored Procedures,我对做更多涉及SQL的工作相当陌生 我的目标是使用查询结果发送电子邮件,以推动电子邮件创建。我打算创建一个存储过程,并计划每周两次,最多20封电子邮件,这在SQLServer2008上不会是很重的电子邮件负载 SELECT ProjectCodes.ProjectCode, COUNT(Projects.ProjectsID), ProjectApprovers.EmailApprover FROM Projects INNER JOIN ProjectCodes ON Projec

我对做更多涉及SQL的工作相当陌生

我的目标是使用查询结果发送电子邮件,以推动电子邮件创建。我打算创建一个存储过程,并计划每周两次,最多20封电子邮件,这在SQLServer2008上不会是很重的电子邮件负载

SELECT ProjectCodes.ProjectCode, COUNT(Projects.ProjectsID),  ProjectApprovers.EmailApprover
FROM Projects 
INNER JOIN ProjectCodes
    ON Projects.ProjectCodesID=ProjectCodes.ProjectCodesID
INNER JOIN ProjectApprovers
    ON Projects.ProjectCodesID=ProjectApprovers.ProjectCodesID
WHERE ProjectApprovers.IsPrimaryApprover=1
group by ProjectCodes.ProjectCode, ProjectApprovers.EmailApprover
这将返回类似于:

+-------------+-------+--------------+
| ProjectCode | Count | EmailAddress |
+-------------+-------+--------------+
| Code1       |     4 | Email1       |
| Code2       |     2 | Email2       |
| Code3       |     2 | Email3       |
| Code4       |     3 | Email4       |
+-------------+-------+--------------+
我想做的基本上是循环这个结果,运行以下命令:

EXEC msdb.dbo.sp_send_dbmail
@recipients= 'email1',     --email address from above query
@subject='Test email',
@body='You have X projects waiting'    -- where X is the COUNT() term
对于每一行

我的理解是,如果我使用游标,我可以对每个条目直接执行此操作,但是,我发现的所有文档和堆栈溢出结果强烈表明,这不是一个好的策略


做这样的事情最好的方法是什么?

通常不鼓励使用游标的原因是,有一些方法可以不使用游标就做你想做的事情。许多开发人员都是从过程语言开始的,因此循环是常见和自然的。根据基于集合的操作进行思考是不自然的,因此使用游标来模拟循环

在这种情况下,使用光标是合适的,因为没有基于集合的方式来发送单独的电子邮件

直接从数据库服务器发送电子邮件是否是一个好主意是另一个问题…

您可以这样做:

创建一个SQL代理作业:该作业将根据您的需要每周调用存储过程两次

您可以在所有SQL Server底部的SSMS上看到此选项并配置设置
您可以通过存储过程控制发送内容或发送对象。

假设这将进入某个临时表或表变量,您可以向该结果集中添加行号,如下所示:

SELECT ROW_NUMBER() OVER (ORDER BY ProjectCodes.ProjectCode) RowNumber, ProjectCodes.ProjectCode, COUNT(Projects.ProjectsID),  ProjectApprovers.EmailApprover
...
然后,使用while循环,迭代该临时表并获取执行SP所需的值,按行号匹配

DECLARE @i int = 0
DECLARE @count int = -- length of query results

WHILE (@i < @count)
BEGIN
    SELECT @emailAddress = EmailApprover, ...
    FROM @YourTempResults
    WHERE RowNumber = (@i + 1) -- row number is 1-based

    EXEC msdb.dbo.sp_send_dbmail @recipients = @emailAddress, ...

    SET @i = @i + 1
END

不过,我们在这里并没有做任何繁重的工作,所以在这种情况下,我不一定建议使用游标。只是时间太长了,我不得不重新学习如何编写代码

您可以定义一个函数,用所需的参数发送邮件。然后在select调用函数的查询上执行select

Select SendPMMail(ProjectCode, EmailAddress, ProjectCount) from
(SELECT ProjectCodes.ProjectCode as ProjectCode, 
        COUNT(Projects.ProjectsID) as ProjectCount, 
        ProjectApprovers.EmailApprover as EmailAddress
   FROM Projects 
  INNER JOIN ProjectCodes
        ON Projects.ProjectCodesID=ProjectCodes.ProjectCodesID
  INNER JOIN ProjectApprovers
        ON Projects.ProjectCodesID=ProjectApprovers.ProjectCodesID
  WHERE ProjectApprovers.IsPrimaryApprover=1
  GROUP BY ProjectCodes.ProjectCode, ProjectApprovers.EmailApprover)

这是使用光标完全合适的情况之一。将查询输出转储到一个临时表中并对其进行迭代。你说的基于集合的操作是什么意思?他的问题是关于如何在结果集中每行执行一个SP,不是如何安排这样的工作。另一个选择是创建一个包含查询中所有信息的表,并基于简单的Case语句,您可以执行发送电子邮件过程。您也可以在一个查询中完成所有操作,但我更喜欢这种方式,因为我发现它更可读。。。我相信其他人也不同意。