it-swarm.com.de

Wie schreibe ich ein foreach in SQL Server?

Ich versuche, etwas in der Art eines for-each zu erreichen, bei dem ich die IDs einer zurückgegebenen select-Anweisung nehmen und jede davon verwenden möchte.

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

Im Moment habe ich etwas, das so aussieht wie oben, aber ich bekomme den Fehler:

Ungültiger Spaltenname "idx".

Könnte jemand 

143
Pomster

Sie möchten eine CURSOR verwenden. In den meisten Fällen ist es am besten, eine satzbasierte Lösung zu verwenden. Manchmal ist jedoch eine CURSOR die beste Lösung. Ohne mehr über Ihr eigentliches Problem zu wissen, können wir Ihnen nicht weiter helfen:

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
275
Lamak

Nehmen wir an, die Spalte PractitionerId ist eindeutig, dann können Sie die folgende Schleife verwenden

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
113

Ihr select count und select max sollte von Ihrer Tabellenvariablen statt von der tatsächlichen Tabelle sein

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
12
Grax

Ich würde sagen, dass wahrscheinlich alles funktioniert, außer dass die Spalte idx in der Tabelle, aus der Sie auswählen, nicht wirklich existiert. Vielleicht wollten Sie aus @Practitioner auswählen:

WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))

weil das im obigen Code so definiert ist:

DECLARE @Practitioner TABLE (
    idx smallint Primary Key IDENTITY(1,1)
    , PractitionerId int
)
4
Mike Perrenoud

Die folgende Zeile ist in Ihrer Version falsch:

WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))

(Fehlt das @)

Es könnte eine Idee sein, Ihre Namenskonvention so zu ändern, dass die Tabellen unterschiedlicher sind.

2
Jon Egerton

Sie benötigen den SQL Server-Cursor.

Dies ist ein MSDN link. Siehe dies für ein einfaches Beispiel.

1
Sameer Azazi

Obwohl Cursor in der Regel als schreckliches Übel betrachtet werden, glaube ich, dass dies ein Fall für den FAST_FORWARD-Cursor ist - der nächste Schritt in TSQL.

1
Yuriy Galanter

Dies funktioniert in der Regel besser als ein Cursor (fast immer) und ist einfacher:

    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
1
David Sopko

Ich habe mir einen sehr effektiven, (ich denke) lesbaren Weg dazu ausgedacht.

    1. create a temp table and put the records you want to iterate in there
    2. use WHILE @@ROWCOUNT <> 0 to do the iterating
    3. to get one row at a time do, SELECT TOP 1 <fieldnames>
        b. save the unique ID for that row in a variable
    4. Do Stuff, then delete the row from the temp table based on the ID saved at step 3b.

Hier ist der Code. Es tut mir leid, es verwendet meine Variablennamen anstelle der in der Frage.

            declare @tempPFRunStops TABLE (ProformaRunStopsID int,ProformaRunMasterID int, CompanyLocationID int, StopSequence int );    

        INSERT @tempPFRunStops (ProformaRunStopsID,ProformaRunMasterID, CompanyLocationID, StopSequence) 
        SELECT ProformaRunStopsID, ProformaRunMasterID, CompanyLocationID, StopSequence from ProformaRunStops 
        WHERE ProformaRunMasterID IN ( SELECT ProformaRunMasterID FROM ProformaRunMaster WHERE ProformaId = 15 )

    -- SELECT * FROM @tempPFRunStops

    WHILE @@ROWCOUNT <> 0  -- << I dont know how this works
        BEGIN
            SELECT TOP 1 * FROM @tempPFRunStops
            -- I could have put the unique ID into a variable here
            SELECT 'Ha'  -- Do Stuff
            DELETE @tempPFRunStops WHERE ProformaRunStopsID = (SELECT TOP 1 ProformaRunStopsID FROM @tempPFRunStops)
        END
0
pdschuller

Hier ist die bessere Lösung.

DECLARE @i int
            DECLARE @curren_val int
            DECLARE @numrows int
            create table #Practitioner (idx int IDENTITY(1,1), PractitionerId int)
            INSERT INTO #Practitioner (PractitionerId) values (10),(20),(30)
            SET @i = 1
            SET @numrows = (SELECT COUNT(*) FROM #Practitioner)
            IF @numrows > 0
            WHILE (@i <= (SELECT MAX(idx) FROM #Practitioner))
            BEGIN

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

                --Do something with Id here
                PRINT @curren_val
                SET @i = @i + 1
            END

Hier habe ich einige Werte in der Tabelle hinzugefügt, weil es anfangs leer ist.

Wir können auf alles zugreifen oder wir können alles im Rumpf der Schleife tun und wir können auf das idx zugreifen, indem wir es in der Tabellendefinition definieren.

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

                --Do something with Id here

                PRINT @curren_val
                SET @i = @i + 1
            END
0
Joseph M