SQL Server 2008'de döngü yaparken yapın


120

do whileSQL Server 2008'de uygulama döngüsü için herhangi bir yöntem var mı ?


5
Rahul'ın verdiği cevap doğru ama tam olarak ne başarmaya çalışıyorsun? Döngüler, set tabanlı çözümlere kıyasla pahalıdır. Belki de bir döngüden tamamen kaçınmak mümkündür.
Lieven Keersmaekers

Mümkünse döngüleri kullanmayın ve zamanın% 95'inde veya daha fazlasında bunlardan kaçınmanın mümkün olduğunu tahmin ediyorum. Döngüler ve imleçler performans katilleridir ve asla en az beş yıllık performans ayarına sahip deneyimli bir DBA olmayan biri tarafından yazılmamalıdır.
HLGEM

1
Er. HLGEM'de biraz dramatik, döngüler ve imleçler, bir tablodaki her satırda döngü yapmadığınız sürece aslında oldukça temizdir. Bir kategori veya site listeniz veya nispeten yüksek düzeyli bir listeniz varsa, sorgunuzu çalıştırmanın en verimli yolu bir döngü olabilir.
Geoff Griswald

Yanıtlar:


190

MS SQL Server 2008'DEKİ DO-WHILE'den emin değilim, ancak WHILE döngü mantığınızı DO-WHILE döngüsü gibi KULLANACAK şekilde değiştirebilirsiniz.

Örnekler buradan alınmıştır: http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of- while-loop-with-continue-and-break-keywords/

  1. WHILE Döngüsü Örneği

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

    Sonuç kümesi:

    1
    2
    3
    4
    5
    
  2. BREAK anahtar kelimeli WHILE Döngüsü örneği

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

    Sonuç kümesi:

    1
    2
    3
    
  3. CONTINUE ve BREAK anahtar kelimelerine sahip WHILE Loop örneği

    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
    

    Sonuç kümesi:

    1
    2
    3
    4
    5
    

Ancak veritabanı düzeyinde döngüleri önlemeye çalışın . Referans .


17
Aynı örnekler burada verilmiştir, bu web sitesinin yazarı siz misiniz? blog.sqlauthority.com/2007/10/24/…
anar khalilov

1
Değil ama neden önemli? Doğru cevap verildi. Başka bir web sitesine bağlantı vermek acı vericidir, cevabı buraya kopyalayıp yapıştırmak faydalıdır.
Geoff Griswald

61

GOTOAnahtar kelimeden çok rahatsız değilseniz, bir T-SQL'de DO/ WHILEiçinde simüle etmek için kullanılabilir . Sözde kodla yazılmış aşağıdaki oldukça saçma örneği düşünün:

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

Goto kullanan eşdeğer T-SQL kodu:

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

GOTOEtkinleştirilmiş çözüm ile orijinal DO/ WHILEsözde kod arasındaki bire bir eşleşmeye dikkat edin . WHILEDöngü kullanan benzer bir uygulama şöyle görünecektir:

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

Şimdi, bu belirli örneği elbette basit bir WHILEdöngü olarak yeniden yazabilirsiniz , çünkü bu a DO/ WHILEconstruct için o kadar iyi bir aday değildir . Vurgu, uygulanabilirlikten ziyade örnek kısalığı üzerineydi, çünkü a DO/ gerektiren meşru davalar WHILEnadirdir.


TEKRARLA / KADAR, herkes (T-SQL'de ÇALIŞMAZ)?

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

... ve GOTOT-SQL'deki temel çözüm:

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

Anahtar kelime aracılığıyla yaratıcı kullanımı GOTOve mantıksal ters çevirme yoluyla NOT, orijinal sözde kod ile GOTOtemelli çözüm arasında çok yakın bir ilişki vardır . WHILEDöngü kullanan benzer bir çözüm şuna benzer:

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

Bir tartışma durumunda söz konusu yapılabilir REPEAT/ UNTIL, WHILEeğer koşul ters olmadığından tabanlı bir çözümdür, daha basittir. Öte yandan, aynı zamanda daha ayrıntılıdır.

Kullanımıyla ilgili tüm küçümseme olmasaydı GOTO, bu belirli (kötü) döngü yapılarının netlik uğruna T-SQL kodunda gerekli olduğu birkaç kez için deyimsel çözümler bile olabilir.

Bunları kendi takdirinize bağlı olarak kullanın ve sizi çok kötü olanı kullanırken yakaladıklarında diğer geliştiricilerinizin gazabına uğramamaya çalışın GOTO.


6
+1: soruya kesinlikle kabul edilen cevaptan daha iyi cevap verir.
Louis Kottmann

Korkunç GOTO kullanmadan amaca işlevsel olarak uyduğundan WHILE (1 = 1) yaklaşımını tercih ediyorum.
kad81

Her iki yöntem de geçerlidir. GOTO kullanan sözde döngüyü seviyorum, oldukça akıllıca.
Geoff Griswald

18

Bu makaleyi bir kereden fazla okuduğumu hatırlıyorum ve cevap sadece ihtiyacım olana yakın .

Genellikle DO WHILET-SQL'de a'ya ihtiyacım olacağını düşündüğümde , bunun nedeni bir imleci yineliyor olmam ve büyük ölçüde optimum netlik (optimum hıza karşılık) arıyorum. T-SQL'de a WHILE TRUE/ IF BREAK.

Sizi buraya getiren senaryo buysa, bu pasaj size biraz zaman kazandırabilir. Aksi takdirde, tekrar hoş geldiniz, ben. Şimdi burada birden fazla olduğumdan emin olabilirim. :)

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

Ne yazık ki, T-SQL döngü işlemini tek başına tanımlamak için bu sonsuz döngüden daha temiz bir yol sunmuyor gibi görünüyor.


İmleç kullanmak, aslında gerekli olandan çok daha fazla kaynak gerektirdiğinden asla iyi bir seçenek değildir.
greektreat

10
@greektreat: Olumsuz oy için teşekkürler :), ama kafam karıştı! "Bir imleç hiçbir zaman iyi bir seçenek değilse", o zaman her zaman iyi bir seçenek olmalıdır, öyleyse neden olumsuz oy verilsin? Cidden, yine de, açıkçası, imleçlerin pek çok pratik kullanımı vardır: özel tablolara karşı, netlik / kısalık> performansın olduğu küçük işlemler için, deterministik işlemlerin mevcut olmadığı bakım görevleri için, belirli işlemlerin atomik bir işlem olarak gerçekleşmesi gerekir, vb. Son durumumda, saklı yordamıma özel bir gelen tablo değişkenini alıyordum. Mutlak bir basmakalıplık asla iyi bir fikir değildir!
shannon

5
@greektreat: Özetle, bazen verileri yinelemek YALNIZCA seçenektir. Sanırım bu durumda hala iyi bir seçenek olmadığını savunabilirsiniz, ancak bu, bu tür bir kodun gereksiz olduğu ve olumsuz oylama gerektirdiği anlamına gelmez.
shannon

1
Sanırım internette, SQL'de döngüleri ve imleçleri kullanan diğer insanlara çok ama çok kızan kudurmuş bir insan ordusu var. Bu web sitesinde, yaklaşık 30 saniye sonra SQL'de bir döngü kullanmaktan bahsediyor olsanız bile, gelen kutunuz, bunları HERHANGİ bir koşulda kullanmamanızı söyleyen cahil insanlarla dolacak ...
Geoff Griswald

4

Kodunuzun biraz daha okunaklı olmasını istiyorsanız bir çıkış değişkeni de kullanabilirsiniz:

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

Bu, daha karmaşık bir döngünüz olduğunda ve mantığı takip etmeye çalıştığınızda muhtemelen daha alakalı olacaktır. Belirtildiği gibi döngüler pahalıdır, bu yüzden mümkünse diğer yöntemleri deneyin ve kullanın.


Demek istediğim ... Veritabanı sunucularımızın herhangi bir anda 10 ila 20 CPU çekirdeğinin boşta olduğu ve depolama denetleyicilerimizin kullanılabilir bant genişliğinin Gigabit cinsinden ölçüldüğü bir çağda yaşıyoruz, bu yüzden bunun geleneksel olduğundan emin değilim " bilgelik "DÖNGÜ = KÖTÜ" hala geçerlidir.
Geoff Griswald

1

Only While Loop resmi olarak SQL sunucusu tarafından desteklenmektedir. Zaten döngü sırasında DO'nun cevabı var . SQL sunucusunda farklı döngü türlerine ulaşmanın yolları hakkında ayrıntılı cevaplar veriyorum.

Biliyorsanız, yine de döngünün ilk yinelemesini tamamlamanız gerekir, o zaman SQL sunucusunun DO..WHILE veya REPEAT..UNTIL sürümünü deneyebilirsiniz .

DO..WHILE Döngüsü

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

REPEAT..UNTIL Döngüsü

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

Döngü için

DECLARE @cnt INT = 0;

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

PRINT 'Done FOR LOOP';

Referans


Bu, stackoverflow.com/a/46362450/8239061 adresinden kopyala-yapıştır-yeniden sıralama gibi görünüyor .
SecretAgentMan

@SecretAgentMan: Her iki yanıt da farklı soruları yanıtlıyor. Her iki cevapta da verilen ek veriler.
Somnath Muluk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.