SQL - 为每条记录调用存储过程

Chr*_*ris 46 sql t-sql sql-server

我正在寻找一种方法来为select语句的每个记录调用存储过程.

SELECT @SomeIds = (
    SELECT spro.Id 
    FROM SomeTable as spro
    INNER JOIN [Address] addr ON addr.Id = spro.Id 
    INNER JOIN City cty ON cty.CityId = addr.CityId
    WHERE cty.CityId = @CityId
)


WHILE @SomeIds  IS NOT NULL
BEGIN
    EXEC UpdateComputedFullText @SomeIds
END
Run Code Online (Sandbox Code Playgroud)

上面这样的事情当然不起作用,但有没有办法做这样的事情?

tre*_*chf 67

您需要使用光标.

DECLARE @oneid int -- or the appropriate type

DECLARE the_cursor CURSOR FAST_FORWARD
FOR SELECT spro.Id  
    FROM SomeTable as spro 
        INNER JOIN [Address] addr ON addr.Id = spro.Id  
        INNER JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId

OPEN the_cursor
FETCH NEXT FROM the_cursor INTO @oneid

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC UpdateComputedFullText @oneid

    FETCH NEXT FROM the_cursor INTO @oneid
END

CLOSE the_cursor
DEALLOCATE the_cursor
Run Code Online (Sandbox Code Playgroud)

  • 游标不是邪恶的 - 这是简单的.如果可能,使用基于集合的解决方案重写迭代解决方案(游标或while循环).如果没有其他信息,您需要在这种情况下进行迭代,并且游标很好. (27认同)
  • 对于OP,请注意游标是邪恶的,你应该不惜一切代价避免它们,但我仍然给它+1,因为在某些情况下使用它们是合理的.希望这是一次性的事情,你不会把这个光标放在另一个proc :) (3认同)
  • (-1) 游标是可怕的,尤其是在 SQL Server 的新版本之后。那和基于 Set 的语法更加优雅和简洁——更不用说更快的数量级了。 (2认同)

Cha*_*ana 21

将Ids放入Temporary表变量,然后遍历每一行:(您不需要使用速度相当慢的游标)

   Declare @Keys Table (key integer Primary Key Not Null)
   Insert @Keys(key)
   SELECT spro.Id  
   FROM SomeTable as spro 
       JOIN [Address] addr ON addr.Id = spro.Id  
       JOIN City cty ON cty.CityId = addr.CityId 
   WHERE cty.CityId = @CityId
   -- -------------------------------------------
   Declare @Key Integer
   While Exists (Select * From @Keys)
     Begin
         Select @Key = Max(Key) From @Keys
         EXEC UpdateComputedFullText @Key
         Delete @Keys Where Key = @Key
     End 
Run Code Online (Sandbox Code Playgroud)

编辑删除在与针对非常窄的唯一索引驱动的过滤谓词一起使用时并不慢,因为这是.但它可以很容易地避免,只需循环如下:

Declare @Key Integer = 0
While Exists (Select * From @Keys
              Where key > @Key)
 Begin
     Select @Key = Min(Key) From @Keys
                   Where key > @Key
     EXEC UpdateComputedFullText @Key
     -- Delete @Keys Where Key = @Key No Longer necessary 
 End    
Run Code Online (Sandbox Code Playgroud)

  • 仅向前只读游标可能比这更好.但当然,必须衡量绩效,以便做出决定. (5认同)
  • 这赢得了我的第一次降压 - 它有4分,但是错误的信息.这将比光标慢,并且什么也得不到.我已经看过使用的模式 - 这是一个需要修复的缺陷.删除是最慢的SQL操作,迭代时不需要成本.一段时间的另一个例子是优选的(来自何塞).快进光标很好.基于集合将是最好的 - 但需要更多信息来提供. (4认同)

Has*_*yed 21

惊讶没有人给你一个最新的答案.游标很糟糕.你想要的是将SP的逻辑移动到表值函数(TVF)然后使用CROSS APPLY

这是我昨天写的一个查询(不要详述细节,只看一下CROSS APPLY).在CROSS APPLY创建表的联合.此联合的每个元素都是从TVF生成的,TVF在select语句的行条目上进行参数化.

SELECT supt.hostname,supt.scriptname, COUNT(*)
FROM Event_Pagehit eph
    INNER JOIN Symboltable_urlpair supf
    ON eph.fromPagePair=supf.id
    INNER JOIN Symboltable_urlpair supt
    ON supt.id=eph.toPagePair
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supf.hostname,supf.scriptname) as x
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supt.hostname,supt.scriptname) as y
WHERE x.isCompanyFormations=1
AND y.isCompanyFormations=0
GROUP BY supt.hostname,supt.scriptname
ORDER BY COUNT(*) desc
Run Code Online (Sandbox Code Playgroud)

我可以使用x,y就好像它们是从FROMJOIN条款中引入的表格一样.如果我不用TVF写这个查询,它将跨越几百行.

注意:

如果无法重写SP:您应该能够从表值函数将结果表中插入存储过程的结果.我从来没有这样做,有时不同的SQL服务器构造有警告 - 所以除非有人说不然我认为是这种情况.


Jos*_*ama 5

不带光标尝试这个

DECLARE @id int 

SELECT top 1 @id = spro.Id   
    FROM SomeTable as spro  
        INNER JOIN [Address] addr ON addr.Id = spro.Id   
        INNER JOIN City cty ON cty.CityId = addr.CityId  
    WHERE cty.CityId = @CityId
    ORDER BY spro.id

WHILE @@ROWCOUNT > 0 
BEGIN 
    EXEC UpdateComputedFullText @id 

    SELECT top 1 @id = spro.Id   
    FROM SomeTable as spro  
        INNER JOIN [Address] addr ON addr.Id = spro.Id   
        INNER JOIN City cty ON cty.CityId = addr.CityId  
    WHERE cty.CityId = @CityId 
    and spro.id > @id
    ORDER BY spro.id
END 
Run Code Online (Sandbox Code Playgroud)

  • 这是没有理由的教条——法律条文而不是法律精神。避免使用游标的主要原因是因为几乎总是有更有效的基于集合的解决方案。这避免了游标,但不提供基于集合的解决方案。当然,我们不知道这个问题存在基于集合的解决方案。 (3认同)
  • (+1) 在 SQL 中进行 TB 级数据处理的同事告诉我,用于迭代的“WHILE”执行得相当好——尤其是在没有选择的情况下——然而如今 TVF + CROSS APPLY = king(参见我的答案)。 (2认同)