Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/EmptyTag/130.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 server 如何在SQL Server存储过程中对用户定义的表类型进行ForEach?_Sql Server_Stored Procedures_Azure Sql Database_User Defined Functions_User Defined Types - Fatal编程技术网

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

Sql server 如何在SQL Server存储过程中对用户定义的表类型进行ForEach?,sql-server,stored-procedures,azure-sql-database,user-defined-functions,user-defined-types,Sql Server,Stored Procedures,Azure Sql Database,User Defined Functions,User Defined Types,IntType是用户定义的表类型 XX PROCEDURE [dbo].[XXX] @X dbo.IntType readonly AS BEGIN SET NOCOUNT ON; // how can I foreach(@X) here and do process individually? END 我需要在SQL Azure中使用它,请给出建议。是ForEach的SQL等价物 但是,游标通常是坏SQL的标志:它们违反了通常基于集合的思想,即SQL是为其构建和优化

IntType是用户定义的表类型

XX PROCEDURE [dbo].[XXX]
    @X dbo.IntType readonly
AS
BEGIN
    SET NOCOUNT ON;
    // how can I foreach(@X) here and do process individually?
END
我需要在SQL Azure中使用它,请给出建议。

是ForEach的SQL等价物

但是,游标通常是坏SQL的标志:它们违反了通常基于集合的思想,即SQL是为其构建和优化的

在SQL cursor或SQL cursor Azure上搜索许多内容和注释


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

您可以做类似的事情:

CREATE TYPE [dbo].[IntType] AS TABLE(
    [T] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [T] ASC
)
为什么不使用光标??? 我不同意你在StackOverflow上找到的许多其他答案。一般来说,你会看到人们对游标有各种各样的不好的说法。。当我们谈论传统餐桌时,他们是对的。。唯一的问题是,您的问题是关于在存储过程中使用的表变量

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

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

让我们看一个基于您的场景的示例。 首先,我们定义一个表类型:

CREATE PROCEDURE [dbo].[testSet]
AS

BEGIN
    SET NOCOUNT ON;

    DECLARE @NumberofIntType            int,
            @RowCount                   int

    -- get the number of items
    SET @NumberofIntType = (SELECT  count(*)
                            FROM dbo.IntType)

    SET @RowCount = 0           -- set the first row to 0

    -- loop through the records 
    -- loop until the rowcount = number of records in your table
    WHILE @RowCount <= @NumberofIntType
        BEGIN
            -- do your process here

            SET @RowCount = @RowCount + 1
        END
END
然后,我们定义一个使用此表作为输入的存储过程:

CREATE TYPE [IntListType] AS TABLE
   (   [T] INT  );
GO
所以,是的,我使用光标进行迭代

请注意,我使用关键字LOCAL和FAST_FORWARD只是为了让优化器清楚地知道,我不打算更新光标,我只会向前滚动,我只会从过程中访问它

我是这样测试的:

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

当我运行@NumberofIntType的程序时,上面答案中有一个小的更正

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

你能概述一下你想对每一行做什么吗?原因是,您应该尽量避免在SQL中像这样循环使用基于集合的操作,以便我们能够更好地提供帮助。当然,我在这里提出了一个新问题:WHILE循环不是基于集合的,而是基于游标的。@MartinSmith您是对的,删除了我的注释,并留下了示例代码。我对这个循环投了反对票。我不认为他应该避免在描述迭代表变量时使用游标。在这一页的其他地方可以看到我基于光标的答案。我仔细地写了我的答案,并且经常说。OP甚至不知道cursor这个词,这表明他们可能不知道使用cursor会以多快的速度破坏SQL的性能。即使在您的示例中,虽然游标不会引起问题,但这意味着如果将表适当地连接到查询中,许多可能的优化将不会被使用。OP没有给出足够的细节来知道他的案例的最佳答案,我认为引导初学者远离光标是正确的。好吧,我再次不同意。我说的是这样一种情况,即已经确定逐行处理是唯一的可能性。这是我论点的基础。在这种情况下,我们仍然在讨论表变量,而不是传统的表,然后引导他远离游标将导致他选择次优解决方案,如基于WHILE+SELECT的解决方案,您可以在本页其他地方看到。但是,没错,如果他首先能够避免逐行处理,那么还有更好的解决方案,即设置基数解决方案。我对此做出了反应:但这还不够:避免游标。当OP特别提到迭代一个表变量,而不是一个传统的表时,这似乎是一种对一般性陈述甚至是误导性陈述的方式。你看到了对他的特定问题有一个基于集合的答案吗?按照OP评论中的链接,您将看到merge语句对他很有效。我们可以同意不同意。我想SQL的新手经常会有这样的感觉,但我真的需要在这里使用循环。因为这是他们熟悉的编程模型。但很少需要循环。它是一个表变量这一事实并没有改变这样一个事实:游标杀死了SQL引擎可以应用的许多潜在优化。例如,我希望执行一个基于集合的调用,在这个调用中,我可以按行分别调用用户定义表中每一行的存储过程。动态sql真的也是一个答案吗?我无法理解为什么没有添加到语言中。谢谢,这很有帮助。
CREATE PROCEDURE [dbo].[testSet]
AS

BEGIN
    SET NOCOUNT ON;

    DECLARE @NumberofIntType            int,
            @RowCount                   int

    -- get the number of items
    SET @NumberofIntType = (SELECT  count(*)
                            FROM dbo.IntType)

    SET @RowCount = 0           -- set the first row to 0

    -- loop through the records 
    -- loop until the rowcount = number of records in your table
    WHILE @RowCount <= @NumberofIntType
        BEGIN
            -- do your process here

            SET @RowCount = @RowCount + 1
        END
END