Синтаксис for-loop у SQL Server


238

Що таке синтаксис forциклу в TSQL?


10
SQL - це зовсім інша мова порівняно з тією, до якої ти звик. Він зосереджений на тому , що , а не як . Ви повідомляєте SQL Server, які результати ви хочете, і дозволяєте зрозуміти, як отримати відповідь. Або, щоб повторно сказати те, що я щойно сказав - у SQL немає циклу for.
Damien_The_Unbeliever

5
WHILE @I < 10; SET @I = @I + 1; BEGIN; ...; END? Однак це не повинно використовуватися для більшості обробки запитів (але іноді потрібно для імперативних маніпуляцій). Багато таких інструкцій / підказок доступні в Google, використовуючи пошук "tsql for loop".

7
Уникайте циклів на користь JOINs та встановлюйте операції.
Одід

2
Якщо ви не є фахівцем у галузі SQL, вам не слід розглянути можливість використання циклу. Існує лише кілька умов, коли потрібна одна, і більшу частину решти часу використання петлі - еквівалент натискання автомобіля, а не керування ним. Навчіться думати з точки зору наборів даних, а не перебирати записи. Лупінг - це функція експертного рівня не тому, що синтаксис важкий, а тому, що вам потрібно точно знати, скільки шкоди ви можете зробити з цим, перш ніж вам буде дозволено його використовувати.
HLGEM

2
Іноді це може бути використано для швидкого виклику тестових даних у тестовій базі даних, які ви просто збираєтесь видалити незабаром після цього в будь-якому разі. У цьому випадку використання цього методу усуває необхідність пройти окрему програму, написану в чомусь подібному на C #, а інженерія не викликає особливих проблем. Знову ж таки, я просто кажу це з точки зору тестових даних.
Panzercrisis

Відповіді:


210

У T-SQL немає FORциклу, він має WHILEцикл
WHILE (Transact-SQL)

WHILE Boolean_expression
BEGIN

END

8
JOIN (і операції з набору) слід віддавати перевагу перед циклічними конструкціями в SQL.
Одід

6
Немає обмежень у наголосі (особливо для тих, хто не є новим у SQL), що Дамієн сказав: "SQL - це зовсім інша мова порівняно з
з'ясує

1
Цікаво відзначити, що документація на MS тут дійсно неправильна. WHILE не приймає булевого виразу - він бере присудок - який, крім того, що може оцінювати ІСТИНА чи ЛАЖНА, також може бути невідомим.
Damien_The_Unbeliever

360

Немає циклу for, а лише цикл while:

DECLARE @i int = 0

WHILE @i < 20
BEGIN
    SET @i = @i + 1
    /* do some work */
END

20
Зауважте, що якщо ви збираєтесь використовувати індекс у циклі, ви можете збільшити останнє, а не перше, залежно від випадку використання.
jinglesthula

3
Також зауважте, що значення за замовчуванням для локальної змінної не підтримується у звичайному SQL. Отже, вам потрібні окремі SET @i = 0раніше для циклу.
Nux

1
@Nux: 0 встановлюється під час декларування явно
TcKs

7
Так, але це не працює на старих серверах SQL (принаймні, не на 2005 рік).
Nux

Також слід зазначити, що загалом робота виконується до збільшення цілого числа. Дуже багато циклів у SQL фактично використовують це ціле число у своїй роботі (повторення з рядка в рядок або результат у результаті виведення темп-таблиць) і може бути скинуто, якщо приріст станеться на початку циклу, а не в кінці.
CSS

34

Додаткова інформація

Тільки щоб додати, як ніхто не опублікував відповідь, яка включає, як насправді ітератувати, хоча набір даних всередині циклу, ви можете використовувати ключові слова OFFSET FETCH .

Використання

DECLARE @i INT = 0;
SELECT @count=  Count(*) FROM {TABLE}

WHILE @i <= @count
BEGIN

    SELECT * FROM {TABLE}
    ORDER BY {COLUMN}
    OFFSET @i ROWS   
    FETCH NEXT 1 ROWS ONLY  

    SET @i = @i + 1;

END

2
Хороша альтернатива використанню курсору.
DanteTheSmith

28

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

13
Ласкаво просимо до переповнення стека! Чи можете ви додати трохи розповіді, щоб пояснити, чому цей код працює, і що робить його відповіддю на питання? Це було б дуже корисно для людини, яка задає це питання, і для всіх, хто приходить разом.
Ендрю Барбер

18
Це само собою зрозуміло.
Едвард Оламісан

4
Як це не пояснюється само собою? У мене було те саме питання, я зрозумів відповідь одразу.
DanteTheSmith

1
Чим ця відповідь відрізняється від @TcKs, крім конвенції про іменування?
Sushil Jadhav

7

Як щодо цього:

BEGIN
   Do Something
END
GO 10

... звичайно, ви можете покласти додатковий лічильник всередині нього, якщо вам потрібно порахувати.


3
'GO 10'? SQL Server 2008 це не любить.
Ресурс

7

Для циклу офіційно ще не підтримується SQL-сервер. Вже є відповідь на досягнення різних циклів FOR Loop. Я деталізую відповідь про способи досягнення різних типів циклів на SQL сервері.

ДЛЯ петлі

DECLARE @cnt INT = 0;

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

PRINT 'Done FOR LOOP';

Якщо ви знаєте, вам потрібно все-таки виконати першу ітерацію циклу, тоді ви можете спробувати DO..WHILE або REPEAT..UNTIL версію SQL-сервера.

ЗРОБИТИ ШЛЯХ

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

ПОВТОРЕННЯ..НЕТИЛЬНА петля

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

Довідково


Це , як видається, були скопійовані вставили-замовлена тут: stackoverflow.com/a/46363319/8239061
SecretAgentMan

@SecretAgentMan: Обидві відповіді відповідають на різні запитання. Додаткові дані наведені в обох відповідях.
Сомнатх Мулук

6

Відповідь проста NO !!.

У FORSQL немає , але ви можете використовувати WHILEабо GOTOдомогтися того, як FORбуде працювати.

ВІД:

DECLARE @a INT = 10

WHILE @a <= 20
BEGIN
    PRINT @a
    SET @a = @a + 1
END

ЙТИ ДО :

DECLARE @a INT = 10
a:
PRINT @a
SET @a = @a + 1
IF @a < = 20
BEGIN
    GOTO a
END

Я завжди віддаю перевагу WHILEнад GOTOтвердженням.


1
Мені подобається, як ти згадав обидві альтернативи, а не лише 1, як більшість відповідей
DanteTheSmith

0

Приклад циклу в T-SQL, в якому вказано дату початку та закінчення поточного місяця.

DECLARE @Today DATE= GETDATE() ,
@StartOfMonth DATE ,
@EndOfMonth DATE;

DECLARE @DateList TABLE ( DateLabel VARCHAR(10) );
SET @EndOfMonth = EOMONTH(GETDATE());
SET @StartOfMonth = DATEFROMPARTS(YEAR(@Today), MONTH(@Today), 1);

WHILE @StartOfMonth <= @EndOfMonth
BEGIN
    INSERT  INTO @DateList
    VALUES  ( @StartOfMonth );
    SET @StartOfMonth = DATEADD(DAY, 1, @StartOfMonth);
END;

SELECT  DateLabel
FROM    @DateList;  

0

Спробуйте, дізнайтеся:

DECLARE @r INT = 5
DECLARE @i INT = 0
DECLARE @F varchar(max) = ''
WHILE @i < @r
BEGIN

    DECLARE @j INT = 0
    DECLARE @o varchar(max) = ''
    WHILE @j < @r - @i - 1
    BEGIN
        SET @o = @o + ' '
        SET @j += 1
    END

    DECLARE @k INT = 0
    WHILE @k < @i + 1
    BEGIN
        SET @o = @o + ' *'  -- '*'
        SET @k += 1
    END
    SET @i += 1
    SET @F = @F + @o + CHAR(13)
END
PRINT @F

З датою:

DECLARE @d DATE = '2019-11-01'
WHILE @d < GETDATE()
BEGIN
    PRINT @d
    SET @d = DATEADD(DAY,1,@d)
END
PRINT 'n'
PRINT @d
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.