在游标循环中声明自定义类型的变量

时间:2016-02-23 13:09:12

标签: tsql sql-server-2012

在对我们项目中的错误进行调查时,我发现了一些对我来说很奇怪的行为。 检查代码:

--CREATE TYPE dbo.test AS TABLE(DocumentVersionId INT, ResourceId INT, Deadline DATE)

DECLARE @documents dbo.test
DECLARE @resourceId INT

INSERT INTO @documents(DocumentVersionId, ResourceId, Deadline)
SELECT * FROM (VALUES(1, 1, GETDATE()),(2, 2, GETDATE()),(3, 3, GETDATE())) T(A, B, C)

DECLARE mails CURSOR FAST_FORWARD FOR
SELECT DISTINCT ResourceId 
FROM @documents

OPEN mails

FETCH NEXT FROM mails INTO @resourceId

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @docs dbo.test

    --DELETE FROM @docs

    INSERT INTO @docs(DocumentVersionId, Deadline)
    SELECT DocumentVersionId, Deadline
    FROM @documents
    WHERE ResourceId = @resourceId

    SELECT * FROM @docs

    FETCH NEXT FROM mails INTO @resourceId
END

CLOSE mails
DEALLOCATE mails

我们有为TVP传输的数据生成邮件的程序。必须在循环(游标)中执行此过程的每次执行才能过滤数据。 问题是,在每次循环迭代中,@ docs变量包含来自先前迭代的数据,即使每次重新创建变量也是如此。

我们每次都可以从这个变量中删除数据,但这不是我们期望的行为。 问题是,为什么会发生这种情况?

enter image description here

1 个答案:

答案 0 :(得分:1)

变量没有局部范围。来自docs

  

变量的范围是可以引用变量的Transact-SQL语句的范围。变量的范围从声明它的位置开始持续到声明它的批处理或存储过程的结束。

这意味着@docs在第一次循环迭代的范围内,直到过程终止。这或多或少是范围在VB6中的工作方式,它确实创造了一些......有趣的范围问题。

您必须在每次迭代中调用DELETE FROM @docs;来清除它