【问题标题】:Loop through all the rows of a temp table and call a stored procedure for each row循环遍历临时表的所有行并为每一行调用一个存储过程
【发布时间】:2014-05-02 08:59:05
【问题描述】:

我已经声明了一个临时表来保存所有必需的值,如下所示:

    DECLARE @temp TABLE
    (
    Password INT,
    IdTran INT,
    Kind VARCHAR(16)
    )

INSERT INTO @temp
SELECT  s.Password, s.IdTran, 'test'
from signal s inner join vefify v 
    on s.Password = v.Password 
and s.IdTran = v.IdTran 
and v.type = 'DEV' 
where s.[Type] = 'start' 
AND NOT EXISTS (SELECT * FROM signal s2
            WHERE s.Password = s2.Password 
            and s.IdTran = s2.IdTran 
            and s2.[Type] = 'progress' )

INSERT INTO @temp
SELECT  s.Password, s.IdTran, 'test'
FROM signal s inner join vefify v 
    on s.Password = v.Password 
and s.IdTran = v.IdTran 
and v.type = 'PROD' 
where s.[Type] = 'progress' 
AND NOT EXISTS (SELECT * FROM signal s2
            WHERE s.Password = s2.Password 
            and s.IdTran = s2.IdTran 
            and s2.[Type] = 'finish' )
            
            
            

现在我需要遍历@temp 表中的行,并为每一行调用一个将@temp 表的所有参数作为输入的sp。 我怎样才能做到这一点?

【问题讨论】:

  • 您的 proc 是否为 @temp 表中的每个值返回多行或单行。如果 proc 只返回单行/值,我会考虑将其重写为调用函数。这样您就可以在没有cursors = CURSESLOOPS 的情况下对表中的每个值执行。 SQL 旨在进行基于集合的处理而不是循环。社区中的大多数人都会避免与cursors 相关的所有事情,这真的是curse

标签: sql sql-server stored-procedures foreach


【解决方案1】:

你可以这样做

    Declare @min int=0, @max int =0 --Initialize variable here which will be use in loop 
    Declare @Recordid int,@TO nvarchar(30),@Subject nvarchar(250),@Body nvarchar(max)  --Initialize variable here which are useful for your

    select ROW_NUMBER() OVER(ORDER BY [Recordid] )  AS Rownumber, Recordid, [To], [Subject], [Body], [Flag]
            into #temp_Mail_Mstr FROM Mail_Mstr where Flag='1'  --select your condition with row number & get into a temp table

    set @min = (select MIN(Rownumber) from #temp_Mail_Mstr); --Get minimum row number from temp table
    set @max = (select Max(Rownumber) from #temp_Mail_Mstr);  --Get maximum row number from temp table

   while(@min <= @max)
   BEGIN
        select @Recordid=Recordid, @To=[To], @Subject=[Subject], @Body=Body from #temp_Mail_Mstr where Rownumber=@min

        -- You can use your variables (like @Recordid,@To,@Subject,@Body) here  
        -- Do your work here 

        set @min=@min+1 --Increment of current row number
    END

【讨论】:

    【解决方案2】:

    你可以使用光标:

    DECLARE @id int
    DECLARE @pass varchar(100)
    
    DECLARE cur CURSOR FOR SELECT Id, Password FROM @temp
    OPEN cur
    
    FETCH NEXT FROM cur INTO @id, @pass
    
    WHILE @@FETCH_STATUS = 0 BEGIN
        EXEC mysp @id, @pass ... -- call your sp here
        FETCH NEXT FROM cur INTO @id, @pass
    END
    
    CLOSE cur    
    DEALLOCATE cur
    

    【讨论】:

    • 我如何将密码、IdTran、Kind 从@temp 传递到存储过程中?
    • 棒极了!我很好奇是否有办法在不使用光标的情况下做到这一点?没有游标会不会更高效(这将运行数十万条记录)?
    • 我不认为没有光标你可以做到这一点。游标的名声有些不好,但它们并没有那么低效。如果您的临时表是几千行,我不会担心...
    • @FETCH_STATUS 变量是一个错字。它应该是@@FETCH_STATUS(2 个&符号)。我尝试编辑上面的脚本,但 SO 需要编辑为 6 个字符或更多。
    【解决方案3】:

    您始终不需要光标。你可以用一个while循环来做到这一点。您应该尽可能避免使用游标。 While 循环比游标快。

    【讨论】:

    • 你在说什么,伙计?
    • 你在问我的朋友什么?你认为你总是需要一个光标?
    • 我并不是说您的说法不正确。我是说你给出了一个错误的答案。您没有解释任何内容,也没有提供有关在哪里可以找到更多信息的指示。你的回答没有任何帮助。
    【解决方案4】:

    像这样?

    DECLARE maxval, val, @ind INT;
    SELECT MAX(ID) as maxval FROM table;
    
    while (ind <= maxval  ) DO           
    
          select `value` as val from `table` where `ID`=ind;
    
          CALL fn(val);
    
          SET ind = ind+1;
    end while;
    

    【讨论】:

    • OP 正在使用 MS SQL。您在此处提供的内容无法在该环境中运行。
    【解决方案5】:

    尝试将数据集从存储过程返回到 C# 或 VB.Net 中的数据表。然后可以使用批量复制将数据表中的大量数据复制到目标表中。我使用 BulkCopy 将具有数千行的大型数据表加载到 Sql 表中,在性能方面取得了巨大成功。

    您可能想在 C# 或 VB.Net 代码中试验 BulkCopy。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-29
      • 1970-01-01
      • 2014-01-02
      • 1970-01-01
      相关资源
      最近更新 更多