如何在SQL Server中编写foreach?

Pom*_*ter 168 t-sql sql-server

我正在尝试按照for-each的方式实现某些内容,我希望获取返回的select语句的ID并使用它们中的每一个.

DECLARE @i int
DECLARE @PractitionerId int
DECLARE @numrows int
DECLARE @Practitioner TABLE (
    idx smallint Primary Key IDENTITY(1,1)
    , PractitionerId int
)

INSERT @Practitioner
SELECT distinct PractitionerId FROM Practitioner

SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM Practitioner)
IF @numrows > 0
    WHILE (@i <= (SELECT MAX(idx) FROM Practitioner))
    BEGIN

        SET @PractitionerId = (SELECT PractitionerId FROM @Practitioner WHERE idx = @i)

        --Do something with Id here
        PRINT @PractitionerId

        SET @i = @i + 1
    END
Run Code Online (Sandbox Code Playgroud)

目前我有一些看起来像上面的东西,但我得到错误:

列名称'idx'无效.

有人可以

Lam*_*mak 312

你似乎想用一个CURSOR.虽然大多数时候最好使用基于集合的解决方案,但有时候a CURSOR是最佳解决方案.如果不了解您的真实问题,我们无法帮助您:

DECLARE @PractitionerId int

DECLARE MY_CURSOR CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR 
SELECT DISTINCT PractitionerId 
FROM Practitioner

OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @PractitionerId
WHILE @@FETCH_STATUS = 0
BEGIN 
    --Do something with Id here
    PRINT @PractitionerId
    FETCH NEXT FROM MY_CURSOR INTO @PractitionerId
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
Run Code Online (Sandbox Code Playgroud)

  • 请不要开始左右使用游标.他们需要<1%的时间.RBAR(通过痛苦的行排)解决方案通常表现不佳并导致头痛.如果您是新手,请尽早学习本课程. (36认同)
  • @CeesTimmerman我知道这已经过时了,但我讨厌留下一个支持光标的评论作为链中的最后一个.为了为每个结果插入多行,*可能*是最佳选项是游标,或者可能是您实际上可以使用连接等来为要插入的每一行生成结果行.通常,这是SQL的更好解决方案.我认为格拉纳达科德可能会得到的是"给一个小男孩一个(光标),他会发现他遇到的一切都需要(迭代)"...... (5认同)
  • 当然,如果你想对循环中的每条记录真正“做”一些事情(比如发送电子邮件或写入文件),而不是仅仅在 SQL 中随机排列内容,那么你需要使用游标或类似的东西(不是`设置`逻辑)。可能接触 SQL 并尝试做一些 RBAR 事情的人,他们是作为一名程序员接触 SQL 的,需要它来做一些像这样有用的事情。 (3认同)

Ale*_*nko 121

假设PractitionerId列是唯一的,那么您可以使用以下循环

DECLARE @PractitionerId int = 0
WHILE(1 = 1)
BEGIN
  SELECT @PractitionerId = MIN(PractitionerId)
  FROM dbo.Practitioner WHERE PractitionerId > @PractitionerId
  IF @PractitionerId IS NULL BREAK
  SELECT @PractitionerId
END
Run Code Online (Sandbox Code Playgroud)

  • @bluelabel退出循环脚本具有以下条件IF PractitionerId IS NULL BREAK (5认同)
  • 太简单了,不可能是真的。您始终在循环内选择 MIN(PractitionerId)。退出循环的条件是什么?对我来说看起来像是一个无限循环。 (2认同)

Gra*_*x32 15

您的选择计数和选择最大值应来自您的表变量而不是实际表

DECLARE @i int
DECLARE @PractitionerId int
DECLARE @numrows int
DECLARE @Practitioner TABLE (
    idx smallint Primary Key IDENTITY(1,1)
    , PractitionerId int
)

INSERT @Practitioner
SELECT distinct PractitionerId FROM Practitioner

SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM @Practitioner)
IF @numrows > 0
    WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
    BEGIN

        SET @PractitionerId = (SELECT PractitionerId FROM @Practitioner WHERE idx = @i)

        --Do something with Id here
        PRINT @PractitionerId

        SET @i = @i + 1
    END
Run Code Online (Sandbox Code Playgroud)


Dav*_*pko 7

通常(几乎总是),它的性能比游标更好,并且更简单:

    DECLARE @PractitionerList TABLE(PracticionerID INT)
    DECLARE @PractitionerID INT

    INSERT @PractitionerList(PracticionerID)
    SELECT PracticionerID
    FROM Practitioner

    WHILE(1 = 1)
    BEGIN

        SET @PracticionerID = NULL
        SELECT TOP(1) @PracticionerID = PracticionerID
        FROM @PractitionerList

        IF @PracticionerID IS NULL
            BREAK

        PRINT 'DO STUFF'

        DELETE TOP(1) FROM @PractitionerList

    END
Run Code Online (Sandbox Code Playgroud)


Mik*_*oud 5

我要说的是,所有内容都可能有效,但idx您选择的表中实际上并不存在该列。也许您打算选择@Practitioner

WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
Run Code Online (Sandbox Code Playgroud)

因为那是在上面的代码中这样定义的:

DECLARE @Practitioner TABLE (
    idx smallint Primary Key IDENTITY(1,1)
    , PractitionerId int
)
Run Code Online (Sandbox Code Playgroud)