Loop while do SQL Server 2008

120

Existe algum método para implementar do whileloop no SQL server 2008?

Nithesh Narayanan
fonte
5
A resposta dada por Rahul está correta, mas o que exatamente você está tentando alcançar? Os loops são caros em comparação com as soluções baseadas em conjuntos. Talvez seja possível evitar um loop completamente.
Lieven Keersmaekers
Não use loops, se possível, e eu estimaria que 95% das vezes ou mais é possível evitá-los. Loops e cursores são prejudiciais ao desempenho e nunca devem ser escritos por alguém que não seja um DBA experiente com pelo menos cinco anos de ajuste de desempenho.
HLGEM
1
Er. um pouco dramático, HLGEM, loops e cursores são realmente muito legais, desde que você não esteja percorrendo todas as linhas de uma tabela. Se você tiver uma lista de categorias ou sites ou algo de nível relativamente alto, um loop poderá ser a maneira mais eficiente de executar sua consulta.
Geoff Griswald

Respostas:

190

Não tenho certeza sobre o DO-WHILE NO MS SQL Server 2008, mas você pode alterar a lógica do loop WHILE, para usar como o loop DO-WHILE.

Exemplos são obtidos aqui: http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of- while - loop - with - continue - and - break - keywords/

  1. Exemplo de loop WHILE

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

    Conjunto de resultados:

    1
    2
    3
    4
    5
  2. Exemplo de loop WHILE com a palavra-chave BREAK

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

    Conjunto de resultados:

    1
    2
    3
  3. Exemplo de loop WHILE com palavras-chave CONTINUE e 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

    Conjunto de resultados:

    1
    2
    3
    4
    5

Mas tente evitar loops no nível do banco de dados. Referência .

Pratik
fonte
17
Os mesmos exemplos são dados aqui, você é o autor deste site? blog.sqlauthority.com/2007/10/24/…
anar khalilov
1
Ele não é, mas por que isso importa? A resposta correta foi dada. Vincular a outro site é doloroso, copiar e colar a resposta aqui é útil.
Geoff Griswald
61

Se você não se ofender com a GOTOpalavra-chave, ela poderá ser usada para simular um DO/ WHILEno T-SQL. Considere o seguinte exemplo sem sentido escrito em pseudocódigo:

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

Aqui está o código T-SQL equivalente usando goto:

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

Observe a 1-1 mapeamento entre a GOTOsolução activada e o original DO/ WHILEpseudocódigo. Uma implementação semelhante usando um WHILEloop seria semelhante a:

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

Agora, é claro que você pode reescrever esse exemplo em particular como um WHILEloop simples , pois esse não é um candidato tão bom para uma DO/ WHILEconstrução. A ênfase foi dada ao exemplo de concisão e não de aplicabilidade, uma vez que casos legítimos que requerem DO/ WHILEsão raros.


REPEAT / ATÉ, alguém (NÃO funciona em T-SQL)?

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

... e a GOTOsolução baseada em T-SQL:

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

Através do uso criativo GOTOe da inversão lógica via NOTpalavra - chave, existe uma relação muito próxima entre o pseudocódigo original e a GOTOsolução baseada. Uma solução semelhante usando um WHILEloop se parece com:

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

Pode-se argumentar que, para o caso de REPEAT/ UNTIL, oWHILE solução baseada é mais simples, porque a condição if não é invertida. Por outro lado, também é mais detalhado.

Se não fosse por todo o desdém pelo uso de GOTO , essas podem até ser soluções idiomáticas para aquelas poucas vezes em que essas construções de loop particulares (más) são necessárias no código T-SQL por uma questão de clareza.

Use-os a seu próprio critério, tentando não sofrer a ira de seus colegas desenvolvedores quando eles pegarem você usando os muito difamados GOTO.

Michael Goldshteyn
fonte
6
+1: definitivamente responde melhor à pergunta do que a resposta aceita.
Louis Kottmann 28/09/12
Prefiro a abordagem WHILE (1 = 1), pois ela se encaixa funcionalmente ao objetivo sem usar o temido GOTO.
kad81
Ambos os métodos são válidos. Eu gosto do pseudo-loop usando GOTO, é bastante inteligente.
Geoff Griswald
18

Lembro-me de ler este artigo mais de uma vez, e a resposta está próxima do que eu preciso.

Normalmente, quando penso que vou precisar de um DO WHILET-SQL, é porque estou repetindo um cursor e procurando em grande parte uma clareza ideal (vs. velocidade ideal). No T-SQL, isso parece se encaixar em um WHILE TRUE/ IF BREAK.

Se esse foi o cenário que trouxe você aqui, esse trecho pode economizar um momento. Caso contrário, bem vindo de volta, eu. Agora posso ter certeza de que estive aqui mais de uma vez. :)

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

Infelizmente, o T-SQL não parece oferecer uma maneira mais limpa de definir a operação de loop individualmente do que esse loop infinito.

Shannon
fonte
Usar um Cursor nunca é uma boa opção, pois exige muito mais recursos que realmente são necessários.
greektreat
10
@greektreat: Obrigado pelo voto negativo :), mas estou confuso! Se "um cursor nunca é uma boa opção", deve sempre ser uma boa opção, então por que o voto negativo? Sério, porém, obviamente, os cursores têm muitos usos bastante práticos: contra tabelas privadas, para pequenas operações em que clareza / brevidade> desempenho, para tarefas de manutenção, onde operações determinísticas não estão disponíveis, pois certas operações devem ocorrer como uma transação atômica, etc. No meu caso recente, eu estava ingerindo uma variável de tabela de entrada, privada ao meu procedimento armazenado. Uma platitude absoluta nunca é uma boa ideia!
Shannon 16/10
5
@greektreat: em resumo, às vezes iterando dados é a única opção. Suponho que você ainda possa argumentar que não é uma boa opção nesse caso, mas isso não significa que esse tipo de código seja desnecessário e precise de voto negativo.
Shannon
1
Eu acho que há um exército raivoso de pessoas na internet que estão muito, muito zangadas com outras pessoas usando loops e cursores no SQL. Neste site se você mesmo tanto como menção usando um loop no SQL cerca de 30 segundos mais tarde sua caixa de entrada será inundado com pessoas ignorantes dizendo que você não usá-los sob quaisquer circunstâncias ...
Geoff Griswald
4

Você também pode usar uma variável de saída se quiser que seu código seja um pouco mais legível:

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

Isso provavelmente seria mais relevante quando você tiver um loop mais complicado e estiver tentando acompanhar a lógica. Como os loops declarados são caros, tente usar outros métodos, se puder.

Sebris87
fonte
Quero dizer ... Vivemos em uma época em que nossos servidores de banco de dados têm entre 10 e 20 núcleos de CPU ociosos a qualquer momento e em que nossos controladores de armazenamento têm sua largura de banda disponível medida em Gigabits, então não tenho certeza se isso é convencional " sabedoria "que" LOOP = BAD "ainda se aplica.
Geoff Griswald
1

Somente While Loop é oficialmente suportado pelo SQL server. Já existe resposta para DO while loop. Estou detalhando a resposta sobre maneiras de obter diferentes tipos de loops no SQL Server.

Se você sabe, você precisa completar primeira iteração do loop de qualquer maneira, então você pode tentar do..while ou repeat..until versão do servidor SQL.

DO..WHILE Loop

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

Repetir..UNTIL Loop

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

Loop FOR

DECLARE @cnt INT = 0;

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

PRINT 'Done FOR LOOP';

Referência

Somnath Muluk
fonte
Isso parece uma cópia-colar-reordenar de stackoverflow.com/a/46362450/8239061 .
SecretAgentMan
@ SecretAgentMan: Ambas as respostas estão respondendo a perguntas diferentes. Dados adicionais fornecidos nas duas respostas.
Somnath Muluk