【问题标题】:How can one iterate over stored procedure results from within another stored procedure....without cursors?如何在另一个存储过程中迭代存储过程结果......没有游标?
【发布时间】:2010-09-14 00:43:01
【问题描述】:

我不确定这是否是我应该在 T-SQL 中做的事情,而且我很确定在这种情况下使用“迭代”这个词是错误的,因为你永远不应该在 sql 中迭代任何东西。它应该是基于集合的操作,对吗?无论如何,这是场景:

我有一个存储过程,它返回许多唯一标识符(单列结果)。这些 id 是另一个表中记录的主键。我需要在该表中的所有相应记录上设置一个标志。

如何在不使用游标的情况下执行此操作?对你来说应该是一个简单的 sql 大师!

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql


    【解决方案1】:

    这可能不是最有效的,但我会创建一个临时表来保存存储过程的结果,然后在与目标表的连接中使用它。例如:

    CREATE TABLE #t (uniqueid int)
    INSERT INTO #t EXEC p_YourStoredProc
    
    UPDATE TargetTable 
    SET a.FlagColumn = 1
    FROM TargetTable a JOIN #t b 
        ON a.uniqueid = b.uniqueid
    
    DROP TABLE #t
    

    【讨论】:

    • 太棒了!我只会在 UPDATE 之后添加一个“DROP TABLE #t”。如果您使用的是 SQL Server 2005,您还可以使用表变量而不是带有 INSERT INTO 的临时表 - 表变量是沙盒化的,并在进程退出时自动销毁。大多数时候它们也更快(存在于内存中)。
    • 都市神话:表变量不在内存中!他们住在 tempDB 中。请不要宣传这个神话!
    • @Joe Pineda,为了完整起见,我添加了放置表。
    • @Mitch:你让我思考,所以我调查了一下,发现:support.microsoft.com/kb/305977 第四季度正是这个——表变量是内存结构吗?不,它们也是在磁盘上创建的。然后,如果内存可用,临时表和表变量都会在内存中处理!!!谢谢!
    【解决方案2】:

    您还可以将存储过程更改为用户定义的函数,该函数返回带有您的唯一标识符的表。您可以直接加入 UDF 并将其视为一个表,从而避免显式创建额外的临时表。此外,您可以在调用函数时将参数传递给函数,这是一个非常灵活的解决方案。

    CREATE FUNCTION dbo.udfGetUniqueIDs
    ()
    RETURNS TABLE 
    AS
    RETURN 
    (
        SELECT uniqueid FROM dbo.SomeWhere
    )
    
    GO
    
    UPDATE dbo.TargetTable 
    SET a.FlagColumn = 1
    FROM dbo.TargetTable a INNER JOIN dbo.udfGetUniqueIDs() b 
        ON a.uniqueid = b.uniqueid
    

    编辑: 这将适用于 SQL Server 2000 及更高版本...

    【讨论】:

    • 好主意,但请记住,并非所有存储过程都可以转换为 UDF,因为它们需要是确定性的,并且只调用其他确定性的代码片段。如果 Kilhoffer 的 SP 是其中之一,他将不得不走临时表路线。
    【解决方案3】:

    将存储过程的结果插入到一个临时表中,并将其连接到要更新的表中:

    INSERT INTO #WorkTable
    EXEC usp_WorkResults
    
    UPDATE DataTable
      SET Flag = Whatever
    FROM DataTable
    INNER JOIN #WorkTable
      ON DataTable.Ket = #WorkTable.Key
    

    【讨论】:

      【解决方案4】:

      如果您升级到 SQL 2008,那么您可以传递表参数,我相信。否则,您将无法使用全局临时表或创建一个永久表,其中包含用于某种进程 ID 的列,以确定对存储过程的哪个调用是相关的。

      您在更改生成 ID 的存储过程方面有多少空间?您可以在其中添加代码来处理它,或者有一个参数可以让您在调用时选择性地标记行。

      【讨论】:

        【解决方案5】:

        使用临时表或表变量(您使用的是 SS2005)。

        虽然,这不是可嵌套的 - 如果存储过程使用该方法,那么您不能将该输出转储到临时表中。

        【讨论】:

          【解决方案6】:

          一个丑陋的解决方案是让您的过程在每次调用它时返回“下一个”id,方法是使用另一个表(或现有表上的某个标志)过滤掉它已经返回的行

          【讨论】:

            【解决方案7】:

            您可以使用带有附加列的临时表或表变量:

            DECLARE @MyTable TABLE (
                Column1 uniqueidentifer,
                ...,
                Checked bit
            )
            
            INSERT INTO @MyTable
            SELECT [...], 0 FROM MyTable WHERE [...]
            
            DECLARE @Continue bit
            SET @Continue = 1
            WHILE (@Continue)
            BEGIN
                SELECT @var1 = Column1,
                       @var2 = Column2,
                       ...
                FROM @MyTable
                WHERE Checked = 1
            
                IF @var1 IS NULL
                    SET @Continue = 0
                ELSE
                BEGIN
            
                    ...
            
                    UPDATE @MyTable SET Checked = 1 WHERE Column1 = @var1
                END
            END
            

            编辑:实际上,在您的情况下,加入会更好;上面的代码是一个无光标迭代,这对你的情况来说是多余的。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-08-12
              • 1970-01-01
              • 1970-01-01
              • 2015-12-21
              • 1970-01-01
              相关资源
              最近更新 更多