【问题标题】:Execute a stored procedure for each row inside a table for each distinct UID为每个不同的 UID 表中的每一行执行存储过程
【发布时间】:2021-11-15 07:37:08
【问题描述】:

我有一个具有唯一 ID 和一组列数的表,如下所示。表中的每一行都有一个 UID,然后每列中都有不同的值。存储过程采用这些值中的每一个(包括 UID)并运行大量其他代码。

运行它会是:

EXEC stored_proc @UID @Col1 @Col2 etc

每个 UID 必须在不同的时间运行,并且该 UID 的每一行都需要同时加载。加载后,脚本需要移动到下一个 UID。

最明显的方法是通过光标,但我没有真正的进展。我已经通过一个游标尝试了这个,它使用了一个只有 UID 的临时表,并且为每一行加入了这个,但遗憾的是它没有工作。

示例表(实际表:大约 5000 行):

UID Version Site QuestionOI GeneralAnswer
212109191425-01 6 AGBNL 4 GENANSWER1
212109191425-01 6 AGBNL 9 NULL
212109191425-01 6 AGBNL 100 NULL
212109191425-01 6 AGBNL 103 NULL
212109191425-03 6 AGFCA 11 NULL
212109191425-03 6 AGFCA 22 NULL
212109191425-05 6 COBAR 4 GENANSWER2
212109191425-05 6 COBAR 9 NULL
212109191425-05 6 COBAR 13 NULL
212109191425-05 6 COBAR 15 NULL

谁能想到一种替代方法/方式来迭代循环遍历每个 UID,然后在 UID 的每一行上运行存储过程?游标的使用不是必需的。

任何帮助将不胜感激,并且将奖励干净且最重要的是快速处理速度(请注意嵌套 SP 需要很少的时间来运行)

谢谢!

这是我按要求尝试的一些代码示例,它似乎循环遍历每一行而不是 UID 然后行。 存储过程将运行而不是第二个打印语句 请注意,出于敏感性原因,我不得不对其进行一些更改。

Declare @ClientID VARCHAR;
Declare @UID VARCHAR;

DECLARE Cur1 CURSOR FOR
    SELECT DISTINCT Site FROM #InsertTable

OPEN Cur1
FETCH NEXT FROM Cur1 INTO @ClientID;
WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT 'Processing ClientID: ' + @ClientID;
    DECLARE Cur2 CURSOR FOR
        SELECT UID FROM #InsertTable Where Site=@ClientID;
    OPEN Cur2;
    FETCH NEXT FROM Cur2 INTO @UID;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT 'Found UID: ' + Cast(@UID as Varchar);
        FETCH NEXT FROM Cur2 INTO @UID;
    END;
    CLOSE Cur2;
    DEALLOCATE Cur2;
    FETCH NEXT FROM Cur1 INTO @ClientID;
END;
PRINT 'DONE';
CLOSE Cur1;
DEALLOCATE Cur1;

【问题讨论】:

  • 不工作,你能发布你的代码吗?游标可以工作,并且是我所知道的在每一行上单独执行 proc 的唯一方法。也就是说,这不是最优化的方法。该程序有什么作用?您可能会考虑是否可以将其重构为基于集合的东西,因此您不必逐行处理(较慢)
  • @SOS 存储过程有很多嵌套插入等,不是我创建的,所以我一定要使用它。
  • col1、col2 代表什么?每次 SP 运行时它们都不同吗?
  • Declare @ClientID VARCHAR; 这是一个坏习惯。始终指定可变长度数据类型的长度。您声明的是单个字符串。无论如何,这可能不应该是 varchar,但这是一个不同的问题。
  • 我会考虑为这个其他存储过程使用表值参数,然后重构该过程,以便它可以处理整个集合而不是单行。

标签: sql sql-server stored-procedures database-cursor


【解决方案1】:

游标可以工作,并且是我所知道的在每一行上单独执行过程的唯一方法。也就是说,这不是最优化的方法。游标几乎总是比基于集合的方法慢。您可能会考虑是否可以对其进行重构,以便避免游标和逐行开销。

 DECLARE @YourCursor CURSOR 
    , @UID VARCHAR(50)
    , @Version INT  
    , @Site VARCHAR(10)
    , @QuestionOI INT   
    , @GeneralAnswer VARCHAR(10);

SET @YourCursor = CURSOR FOR
    SELECT [UID]
        , [Version] 
        , [Site] 
        , QuestionOI 
        , GeneralAnswer
    FROM YourTable
    ORDER BY [UID];

OPEN @YourCursor;  

--- load first row           
FETCH NEXT FROM @YourCursor 
INTO @UID, @Version, @Site, @QuestionOI, @GeneralAnswer 

WHILE @@FETCH_STATUS = 0  
BEGIN  
        --- execute proc 
        EXEC stored_proc @UID, @Version, @Site, other variables...
      
        --- get next row           
        FETCH NEXT FROM @YourCursor 
        INTO @UID, @Version, @Site, @QuestionOI, @GeneralAnswer 
END;  
CLOSE @YourCursor;  
DEALLOCATE @YourCursor;  
GO  

【讨论】:

  • 您好,感谢您的回复。正确的是,这个光标可以逐行工作,我有类似的工作。问题是一次只能运行一个 UID 的附加层。例如,在移动到下一个 UID(存储过程中的约束)之前,必须为所有行运行 UID 212109191425-01,然后它需要移动到下一个 UID 212109191425-03
  • 是的,上面的光标会一次执行一个UID。我只是提到通常可以重构逻辑来做同样的事情——但一条记录有多个。我已经用遗留程序做了很多。
  • 您可能需要在 SELECT 游标中添加 ORDER BY UID 确保所有 UID 记录按顺序处理,并且所有相同的 UID 同时处理
  • @SteveFord - 啊,很好。我错过了 UID 的重复。 Pandasman - 你只需要 UID 值来执行 proc - 还是其他列?顺序重要吗?
  • @SOS 是的,看起来 ORDER BY 可以阻止重复。存储过程也使用 UID 和所有列,UID 之后的顺序无关紧要,所以我认为这可以工作。
猜你喜欢
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 2017-10-14
  • 2010-10-05
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多