如何在SQL Server存储过程中对用户定义的表类型执行ForEach?

Eri*_*Yin 2 sql-server stored-procedures user-defined-functions user-defined-types azure-sql-database

XX PROCEDURE [dbo].[XXX]
    @X dbo.IntType readonly
AS
BEGIN
    SET NOCOUNT ON;
    // how can I foreach(@X) here and do process individually?
END
Run Code Online (Sandbox Code Playgroud)

IntType 是用户定义的表类型

CREATE TYPE [dbo].[IntType] AS TABLE(
    [T] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [T] ASC
)
Run Code Online (Sandbox Code Playgroud)

我需要在SQL Azure中使用它,请提供建议.

pet*_*erh 11

为什么不使用游标???

我不同意你在StackOverflow上找到的许多其他答案.一般来说,你会看到人们对游标有各种各样的不好的事情......当我们谈论传统表时它们是对的..唯一的问题是你的问题是关于你在存储过程中使用的表变量.

您的第一个决策点应始终是查看是否可以执行基于集合的操作而不是迭代(逐行处理).数据库针对前者进行了优化.我在这里给出的答案是那些已经决定他们无法使用基于集合的方法并且迭代目标是表变量的人.

您的表变量就像编程语言中的Collection一样.它是一个私有的内存结构.当您在存储过程中时,在ForEach样式中迭代它绝对没有问题.如果您的场景确实需要逐行处理,那么光标在您的情况下肯定是可以的.我真的不明白为什么不.

我们来看一个基于你的场景的例子.首先我们定义一个表类型:

CREATE TYPE [IntListType] AS TABLE
   (   [T] INT  );
GO
Run Code Online (Sandbox Code Playgroud)

然后我们定义一个使用该表作为输入的存储过程:

CREATE PROCEDURE [myTest]
 (
       @IntListInput IntListType READONLY
 )
 AS
 BEGIN
    SET NOCOUNT ON;

    DECLARE @myInt INT;
    DECLARE intListCursor CURSOR LOCAL FAST_FORWARD
    FOR
    SELECT [T]
    FROM @IntListInput;

    OPEN intListCursor;

    -- Initial fetch attempt
    FETCH NEXT FROM intListCursor INTO @myInt;

    WHILE @@FETCH_STATUS = 0
    BEGIN
       -- Here we do some kind of action that requires us to 
       -- process the table variable row-by-row. This example simply
       -- uses a PRINT statement as that action (not a very good
       -- example).
       PRINT 'Int var is : ' + CONVERT(VARCHAR(max),@myInt);

       -- Attempt to fetch next row from cursor
       FETCH NEXT FROM intListCursor INTO @myInt;
    END;

    CLOSE intListCursor;
    DEALLOCATE intListCursor;
 END;
 GO
Run Code Online (Sandbox Code Playgroud)

所以,是的,我使用游标进行迭代.

请注意,我使用关键字LOCAL,FAST_FORWARD只是为了使优化器非常清楚(显式),我不打算更新我的光标,我只会向前滚动,我只会从过程中访问它.

我测试了这样:

DECLARE @IntList IntListType;

-- Put some random data into our list
INSERT INTO @IntList VALUES (33);
INSERT INTO @IntList VALUES (777);
INSERT INTO @IntList VALUES (845);
INSERT INTO @IntList VALUES (71);


EXEC myTest @IntList;
GO
Run Code Online (Sandbox Code Playgroud)


Jam*_*e F 3

游标是 SQL 中的 ForEach 等价物,

但游标通常是 SQL 不良的标志:它们违反了 SQL 构建和优化的通常基于集合的思维。

搜索SQL cursorSQL Cursor Azure查找许多示例教程优化说明。

但这一点还不够:避免游标:它们通常是 SQL 中其他语言的程序员的拐杖,而且它们通常很慢且难以维护。