ทำในขณะที่วนซ้ำใน SQL Server 2008


120

มีวิธีใดในการใช้งานdo whileลูปใน SQL Server 2008 หรือไม่?


5
คำตอบที่ราหุลให้นั้นถูกต้อง แต่คุณพยายามทำอะไรให้สำเร็จ? ลูปมีราคาแพงเมื่อเทียบกับโซลูชันที่กำหนด บางทีอาจเป็นไปได้ที่จะหลีกเลี่ยงการวนซ้ำโดยสิ้นเชิง
Lieven Keersmaekers

อย่าใช้ลูปถ้าเป็นไปได้และฉันจะประมาณว่า 95% ของเวลาหรือมากกว่านั้นเป็นไปได้ที่จะหลีกเลี่ยง ลูปและเคอร์เซอร์เป็นตัวทำลายประสิทธิภาพและไม่ควรเขียนโดยใครก็ตามที่ไม่ใช่ DBA ที่มีประสบการณ์โดยมีการปรับแต่งประสิทธิภาพอย่างน้อยห้าปี
HLGEM

1
เอ้อ HLGEM ที่น่าทึ่งเล็กน้อยลูปและเคอร์เซอร์นั้นค่อนข้างเรียบร้อยตราบใดที่คุณไม่วนซ้ำทุกแถวในตาราง หากคุณมีรายการหมวดหมู่หรือไซต์หรือสิ่งที่ค่อนข้างสูงการวนซ้ำอาจเป็นวิธีที่มีประสิทธิภาพที่สุดในการเรียกใช้การสืบค้นของคุณ
Geoff Griswald

คำตอบ:


190

ฉันไม่แน่ใจเกี่ยวกับ DO-WHILE ใน MS SQL Server 2008 แต่คุณสามารถเปลี่ยนตรรกะการวนซ้ำในขณะที่ใช้เช่น DO-WHILE loop

ตัวอย่างนำมาจากที่นี่: http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of- while-loop-with-continue-and-break-keywords/

  1. ตัวอย่าง WHILE Loop

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
    END
    GO
    

    ResultSet:

    1
    2
    3
    4
    5
    
  2. ตัวอย่าง WHILE Loop พร้อมคำหลัก BREAK

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
        IF @intFlag = 4
            BREAK;
    END
    GO
    

    ResultSet:

    1
    2
    3
    
  3. ตัวอย่าง WHILE Loop ที่มีคำหลัก CONTINUE และ BREAK

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
        CONTINUE;
        IF @intFlag = 4 -- This will never executed
            BREAK;
    END
    GO
    

    ResultSet:

    1
    2
    3
    4
    5
    

แต่พยายามหลีกเลี่ยงการวนซ้ำในระดับฐานข้อมูล ข้อมูลอ้างอิง .


17
มีตัวอย่างเดียวกันนี้คุณเป็นผู้เขียนเว็บไซต์นี้หรือไม่? blog.sqlauthority.com/2007/10/24/…
anar khalilov

1
เขาไม่ได้ แต่ทำไมมันถึงสำคัญ? ได้รับคำตอบที่ถูกต้อง การลิงก์ไปยังเว็บไซต์อื่นเป็นเรื่องยากการคัดลอกและวางคำตอบที่นี่มีประโยชน์
Geoff Griswald

61

หากคุณไม่รู้สึกขุ่นเคืองกับGOTOคีย์เวิร์ดมากนักสามารถใช้เพื่อจำลอง a DO/ WHILEใน T-SQL พิจารณาตัวอย่างที่ค่อนข้างไร้สาระต่อไปนี้ที่เขียนด้วยรหัสเทียม:

SET I=1
DO
 PRINT I
 SET I=I+1
WHILE I<=10

นี่คือรหัส T-SQL ที่เทียบเท่าโดยใช้ goto:

DECLARE @I INT=1;
START:                -- DO
  PRINT @I;
  SET @I+=1;
IF @I<=10 GOTO START; -- WHILE @I<=10

สังเกตการแมปแบบหนึ่งต่อหนึ่งระหว่างGOTOโซลูชันที่เปิดใช้งานและโค้ดต้นฉบับDO/ WHILEpseudocode การใช้งานที่คล้ายกันโดยใช้WHILEลูปจะมีลักษณะดังนี้:

DECLARE @I INT=1;
WHILE (1=1)              -- DO
 BEGIN
  PRINT @I;
  SET @I+=1;
  IF NOT (@I<=10) BREAK; -- WHILE @I<=10
 END

ตอนนี้คุณสามารถเขียนตัวอย่างเฉพาะนี้ใหม่เป็นWHILEลูปง่ายๆได้เนื่องจากนี่ไม่ใช่ตัวเลือกที่ดีสำหรับ a DO/ WHILEconstruction เน้นไปที่ตัวอย่างความสั้นมากกว่าการบังคับใช้เนื่องจากกรณีที่ถูกต้องตามกฎหมายที่ต้องใช้ a DO/ WHILEนั้นหายาก


ทำซ้ำ / จนกว่าทุกคน (ไม่ทำงานใน T-SQL)?

SET I=1
REPEAT
  PRINT I
  SET I=I+1
UNTIL I>10

... และGOTOโซลูชันที่ใช้ใน T-SQL:

DECLARE @I INT=1;
START:                    -- REPEAT
  PRINT @I;
  SET @I+=1;
IF NOT(@I>10) GOTO START; -- UNTIL @I>10

ด้วยการใช้งานอย่างสร้างสรรค์GOTOและการผกผันตรรกะผ่านNOTคำหลักมีความสัมพันธ์ใกล้ชิดกันมากระหว่างรหัสเทียมดั้งเดิมและGOTOโซลูชันที่ใช้ วิธีแก้ปัญหาที่คล้ายกันโดยใช้WHILEลูปมีลักษณะดังนี้:

DECLARE @I INT=1;
WHILE (1=1)       -- REPEAT
 BEGIN
  PRINT @I;
  SET @I+=1;
  IF @I>10 BREAK; -- UNTIL @I>10
 END

อาร์กิวเมนต์สามารถทำว่าสำหรับกรณีของREPEAT/ UNTILการWHILEแก้ปัญหาตามจะง่ายเพราะถ้าเงื่อนไขไม่ได้กลับ ในทางกลับกันมันก็มีรายละเอียดมากขึ้นเช่นกัน

หากไม่ใช่เพื่อการดูถูกเหยียดหยามในการใช้งานGOTOสิ่งเหล่านี้อาจเป็นวิธีแก้ปัญหาสำหรับสองสามครั้งเมื่อโครงสร้างการวนซ้ำ (ชั่วร้าย) เหล่านี้เป็นสิ่งจำเป็นในรหัส T-SQL เพื่อความชัดเจน

ใช้เหล่านี้ขึ้นอยู่กับดุลยพินิจของคุณเองพยายามที่จะไม่ประสบความโกรธเกรี้ยวของนักพัฒนาเพื่อนของคุณเมื่อพวกเขาจับคุณใช้มาก GOTOmaligned


6
+1: ตอบคำถามได้ดีกว่าคำตอบที่ยอมรับ
Louis Kottmann

ฉันชอบวิธี WHILE (1 = 1) เนื่องจากเหมาะกับวัตถุประสงค์ในการใช้งานโดยไม่ต้องใช้ GOTO ที่น่ากลัว
kad81

ทั้งสองวิธีใช้ได้ ฉันชอบการวนซ้ำหลอกโดยใช้ GOTO มันค่อนข้างฉลาด
Geoff Griswald

18

ดูเหมือนฉันจะจำได้ว่าอ่านบทความนี้มากกว่าหนึ่งครั้งและคำตอบก็ใกล้เคียงกับสิ่งที่ฉันต้องการเท่านั้น

โดยปกติเมื่อฉันคิดว่าฉันจะต้องใช้DO WHILET-SQL นั่นเป็นเพราะฉันกำลังทำเคอร์เซอร์ซ้ำและฉันกำลังมองหาส่วนใหญ่เพื่อความชัดเจนที่ดีที่สุด (เทียบกับความเร็วที่เหมาะสม) ใน T-SQL ที่ดูเหมือนว่าจะพอดีกับ a WHILE TRUE/ IF BREAK.

หากนั่นเป็นสถานการณ์ที่ทำให้คุณมาที่นี่ตัวอย่างข้อมูลนี้อาจช่วยคุณได้สักครู่ มิฉะนั้นยินดีต้อนรับกลับฉัน ตอนนี้ฉันมั่นใจได้ว่าฉันเคยมาที่นี่มากกว่าหนึ่งครั้ง :)

DECLARE Id INT, @Title VARCHAR(50)
DECLARE Iterator CURSOR FORWARD_ONLY FOR
SELECT Id, Title FROM dbo.SourceTable
OPEN Iterator
WHILE 1=1 BEGIN
    FETCH NEXT FROM @InputTable INTO @Id, @Title
    IF @@FETCH_STATUS < 0 BREAK
    PRINT 'Do something with ' + @Title
END
CLOSE Iterator
DEALLOCATE Iterator

น่าเสียดายที่ T-SQL ดูเหมือนจะไม่มีวิธีที่สะอาดกว่าในการกำหนดการทำงานของลูปแบบเดี่ยว ๆ มากกว่าการวนซ้ำแบบไม่มีที่สิ้นสุดนี้


การใช้เคอร์เซอร์ไม่ใช่ตัวเลือกที่ดีเนื่องจากต้องใช้ทรัพยากรมากกว่าที่จำเป็นจริงๆ
greektreat

10
@greektreat: ขอบคุณสำหรับการโหวตลงคะแนน :) แต่ฉันสับสน! หาก "เคอร์เซอร์ไม่เคยไม่ใช่ตัวเลือกที่ดี" ก็จะต้องเป็นตัวเลือกที่ดีเสมอไปทำไมจึงต้องโหวตลง? อย่างจริงจังเห็นได้ชัดว่าเคอร์เซอร์มีประโยชน์ในทางปฏิบัติมากมาย: กับตารางส่วนตัวสำหรับการดำเนินงานขนาดเล็กที่ความชัดเจน / ความกะทัดรัด> ประสิทธิภาพสำหรับงานบำรุงรักษาซึ่งการดำเนินการที่กำหนดไม่พร้อมใช้งานสำหรับการดำเนินการบางอย่างจะต้องเกิดขึ้นเป็นธุรกรรมอะตอมโดยไม่คำนึงถึง ฯลฯ ในกรณีล่าสุดของฉันฉันกำลังนำเข้าตัวแปรตารางขาเข้าส่วนตัวไปยังขั้นตอนการจัดเก็บของฉัน ความสงบอย่างแท้จริงไม่ใช่ความคิดที่ดี!
แชนนอน

5
@greektreat: โดยสรุปบางครั้งการทำซ้ำข้อมูลเป็นตัวเลือกเดียว ฉันคิดว่าคุณยังคงสามารถโต้แย้งได้ว่ามันไม่ใช่ตัวเลือกที่ดีในกรณีนั้น แต่นั่นไม่ได้หมายความว่ารหัสประเภทนี้ไม่จำเป็นและต้องลงคะแนน
แชนนอน

1
ฉันคิดว่ามีกองทัพที่บ้าคลั่งของผู้คนบนอินเทอร์เน็ตที่โกรธมากเกี่ยวกับคนอื่นที่ใช้ลูปและเคอร์เซอร์ใน SQL ในเว็บไซต์นี้หากคุณพูดถึงการใช้วนซ้ำใน SQL ประมาณ 30 วินาทีต่อมากล่องจดหมายของคุณจะเต็มไปด้วยผู้คนที่ไม่รู้ว่าจะใช้ไม่ว่าในสถานการณ์ใด ๆ ...
Geoff Griswald

4

คุณยังสามารถใช้ตัวแปร exit หากต้องการให้โค้ดของคุณอ่านง่ายขึ้น:

DECLARE @Flag int = 0
DECLARE @Done bit = 0

WHILE @Done = 0 BEGIN
    SET @Flag = @Flag + 1
    PRINT @Flag
    IF @Flag >= 5 SET @Done = 1
END

สิ่งนี้น่าจะเกี่ยวข้องมากขึ้นเมื่อคุณมีลูปที่ซับซ้อนมากขึ้นและพยายามติดตามตรรกะ ตามที่ระบุไว้ลูปมีราคาแพงดังนั้นลองใช้วิธีอื่น ๆ หากทำได้


ฉันหมายถึง ... เราอยู่ในยุคที่เซิร์ฟเวอร์ฐานข้อมูลของเรามีแกน CPU ระหว่าง 10 ถึง 20 คอร์ไม่ได้ใช้งานในช่วงเวลาใดเวลาหนึ่งและที่ใดก็ตามที่ตัวควบคุมการจัดเก็บข้อมูลของเรามีแบนด์วิดท์ที่พร้อมใช้งานซึ่งวัดเป็นกิกะบิตดังนั้นฉันจึงไม่แน่ใจว่าปกตินี้ " ภูมิปัญญา "ที่" LOOP = BAD "ยังคงใช้อยู่
Geoff Griswald

1

เซิร์ฟเวอร์ SQL รองรับเฉพาะ While Loop เท่านั้น มีคำตอบสำหรับ DO ในขณะที่วนซ้ำอยู่แล้ว ฉันกำลังอธิบายรายละเอียดเกี่ยวกับวิธีการบรรลุลูปประเภทต่างๆในเซิร์ฟเวอร์ SQL

ถ้าคุณรู้ว่าคุณต้องดำเนินการซ้ำครั้งแรกของวงต่อไปแล้วคุณสามารถลองDO..WHILEหรือREPEAT..UNTILรุ่นของเซิร์ฟเวอร์ SQL

DO..WHILE วน

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

ทำซ้ำ .. UNTIL Loop

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

สำหรับห่วง

DECLARE @cnt INT = 0;

WHILE @cnt < 10
BEGIN
   PRINT 'Inside FOR LOOP';
   SET @cnt = @cnt + 1;
END;

PRINT 'Done FOR LOOP';

การอ้างอิง


นี้ดูเหมือนว่าการคัดลอกวางสั่งซื้อใหม่จากstackoverflow.com/a/46362450/8239061
SecretAgentMan

@SecretAgentMan: ทั้งสองคำตอบกำลังตอบคำถามที่แตกต่างกัน ให้ข้อมูลเพิ่มเติมในทั้งสองคำตอบ
Somnath Muluk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.