Thực hiện vòng lặp while trong SQL Server 2008


120

Có phương pháp nào cho do whilevòng lặp thực hiện trong SQL server 2008 không?


5
Câu trả lời mà Rahul đưa ra là đúng nhưng chính xác thì bạn đang cố gắng đạt được điều gì? Các vòng lặp là tốn kém so với các giải pháp dựa trên bộ. Có lẽ hoàn toàn có thể tránh được một vòng lặp.
Lieven Keersmaekers

Không sử dụng vòng lặp nếu có thể và tôi ước tính rằng 95% thời gian hoặc hơn có thể tránh được chúng. Vòng lặp và con trỏ là những kẻ giết hiệu suất và không bao giờ được viết bởi bất kỳ ai không phải là DBA có kinh nghiệm với ít nhất năm năm điều chỉnh hiệu suất.
HLGEM

1
Ờ. hơi ấn tượng ở đó HLGEM, các vòng lặp và con trỏ thực sự khá gọn gàng miễn là bạn không lặp lại mọi hàng trong bảng. Nếu bạn có một danh sách các danh mục hoặc trang web hoặc một cái gì đó tương đối cao, thì một vòng lặp có thể là cách hiệu quả nhất để chạy truy vấn của bạn.
Geoff Griswald

Câu trả lời:


190

Tôi không chắc chắn về DO-WHILE TRONG MS SQL Server 2008 nhưng bạn có thể thay đổi logic vòng lặp WHILE của mình, để SỬ DỤNG như vòng lặp DO-WHILE.

Ví dụ được lấy từ đây: http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of- Regi-loop-with-continue-and-break-keywords/

  1. Ví dụ về WHILE Loop

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

    Kết quả:

    1
    2
    3
    4
    5
    
  2. Ví dụ về Vòng lặp WHILE với từ khóa BREAK

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

    Kết quả:

    1
    2
    3
    
  3. Ví dụ về WHILE Loop với các từ khóa CONTINUE và 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
    

    Kết quả:

    1
    2
    3
    4
    5
    

Nhưng cố gắng tránh các vòng lặp ở cấp cơ sở dữ liệu. Tham khảo .


17
Các ví dụ tương tự được đưa ra ở đây, bạn có phải là tác giả của trang web này không? blog.sqlauthority.com/2007/10/24/…
anar khalilov

1
Anh ấy không, nhưng tại sao nó lại quan trọng? Câu trả lời chính xác đã được đưa ra. Liên kết đến một trang web khác là một điều khó khăn, sao chép và dán câu trả lời ở đây rất hữu ích.
Geoff Griswald

61

Nếu bạn không cảm thấy khó chịu với GOTOtừ khóa, nó có thể được sử dụng để mô phỏng a DO/ WHILEtrong T-SQL. Hãy xem xét ví dụ khá vô lý sau được viết bằng mã giả:

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

Đây là mã T-SQL tương đương sử dụng goto:

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

Lưu ý ánh xạ 1-1 giữa GOTOgiải pháp đã kích hoạt và mã gốc DO/ WHILEgiả. Một cách triển khai tương tự bằng cách sử dụng một WHILEvòng lặp sẽ giống như sau:

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

Bây giờ, tất nhiên bạn có thể viết lại ví dụ cụ thể này dưới dạng một WHILEvòng lặp đơn giản , vì đây không phải là một ứng cử viên tốt cho một cấu trúc DO/ WHILE. Sự nhấn mạnh là tính ngắn gọn của ví dụ hơn là khả năng áp dụng, vì các trường hợp hợp pháp yêu cầu a DO/ WHILErất hiếm.


REPEAT / UNTIL, bất kỳ ai (KHÔNG làm việc trong T-SQL)?

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

... và GOTOgiải pháp dựa trên T-SQL:

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

Thông qua việc sử dụng sáng tạo GOTOvà đảo ngược logic thông qua NOTtừ khóa, có một mối quan hệ rất chặt chẽ giữa mã giả gốc và GOTOgiải pháp dựa trên. Một giải pháp tương tự bằng cách sử dụng một WHILEvòng lặp trông giống như:

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

Có thể lập luận rằng đối với trường hợp của REPEAT/ UNTIL, WHILEgiải pháp dựa trên đơn giản hơn, bởi vì điều kiện if không bị đảo ngược. Mặt khác, nó cũng dài dòng hơn.

Nếu không phải vì tất cả sự khinh thường xung quanh việc sử dụng GOTO, đây thậm chí có thể là các giải pháp thành ngữ cho những trường hợp ít khi các cấu trúc lặp (ác) cụ thể này cần thiết trong mã T-SQL vì mục đích rõ ràng.

Sử dụng những thứ này theo quyết định của riêng bạn, cố gắng không hứng chịu sự phẫn nộ của các nhà phát triển đồng nghiệp của bạn khi họ bắt bạn bằng cách sử dụng nhiều ác ý GOTO.


6
+1: chắc chắn trả lời câu hỏi tốt hơn câu trả lời được chấp nhận.
Louis Kottmann

Tôi thích phương pháp WHILE (1 = 1) hơn, vì nó phù hợp với mục đích về mặt chức năng mà không sử dụng GOTO đáng sợ.
kad81

Cả hai phương pháp đều hợp lệ. Tôi thích vòng lặp giả sử dụng GOTO, nó khá thông minh.
Geoff Griswald

18

Tôi dường như nhớ lại đã đọc bài báo này nhiều hơn một lần, và câu trả lời chỉ gần với những gì tôi cần.

Thông thường khi tôi nghĩ rằng tôi sẽ cần một DO WHILEtrong T-SQL, đó là bởi vì tôi đang lặp lại một con trỏ và phần lớn tôi đang tìm kiếm sự rõ ràng tối ưu (so với tốc độ tối ưu). Trong T-SQL có vẻ phù hợp với a WHILE TRUE/ IF BREAK.

Nếu đó là tình huống đưa bạn đến đây, đoạn mã này có thể giúp bạn tiết kiệm một chút thời gian. Nếu không, chào mừng trở lại, tôi. Bây giờ tôi có thể chắc chắn rằng tôi đã ở đây nhiều hơn một lần. :)

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

Thật không may, T-SQL dường như không cung cấp một cách rõ ràng hơn để xác định đơn lẻ hoạt động của vòng lặp, hơn vòng lặp vô hạn này.


Sử dụng Con trỏ không bao giờ là một lựa chọn tốt vì nó cần nhiều tài nguyên hơn thực sự cần thiết.
greektreat

10
@greektreat: Cảm ơn vì đã downvote :), nhưng tôi bối rối! Nếu "con trỏ không bao giờ là một lựa chọn tốt", thì nó luôn phải là một lựa chọn tốt, vậy tại sao lại là một lựa chọn không tốt? Mặc dù vậy, nghiêm túc mà nói, rõ ràng con trỏ có nhiều cách sử dụng khá thực tế: chống lại các bảng riêng tư, cho các hoạt động nhỏ trong đó rõ ràng / ngắn gọn> hiệu suất, cho các tác vụ bảo trì, nơi các hoạt động xác định không có sẵn, đối với các hoạt động nhất định phải xảy ra như một giao dịch nguyên tử bất kể, v.v. Trong trường hợp gần đây của tôi, tôi đang nhập một biến bảng đến, riêng tư đối với thủ tục đã lưu trữ của tôi. Một sự đa dạng tuyệt đối không bao giờ là một ý kiến ​​hay!
shannon

5
@greektreat: tóm lại, đôi khi lặp lại dữ liệu là lựa chọn DUY NHẤT. Tôi cho rằng bạn vẫn có thể tranh luận rằng nó không phải là một lựa chọn tốt trong trường hợp đó, nhưng điều đó không có nghĩa là loại mã này là không cần thiết và cần phản đối.
shannon

1
Tôi nghĩ rằng có một đội quân điên cuồng trên internet, những người rất rất tức giận về việc người khác sử dụng vòng lặp và con trỏ trong SQL. Trên trang web này nếu bạn thậm chí đề cập đến việc sử dụng vòng lặp trong SQL khoảng 30 giây sau hộp thư đến của bạn sẽ tràn ngập những người thiếu hiểu biết bảo bạn không sử dụng chúng trong BẤT KỲ trường hợp nào ...
Geoff Griswald

4

Bạn cũng có thể sử dụng biến thoát nếu bạn muốn mã của mình dễ đọc hơn một chút:

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

Điều này có thể phù hợp hơn khi bạn có một vòng lặp phức tạp hơn và đang cố gắng theo dõi logic. Như đã nêu, các vòng lặp rất tốn kém, vì vậy hãy thử và sử dụng các phương pháp khác nếu bạn có thể.


Ý tôi là ... Chúng ta đang sống trong thời đại mà các máy chủ cơ sở dữ liệu của chúng ta có từ 10 đến 20 lõi CPU không hoạt động tại bất kỳ thời điểm nào và nơi bộ điều khiển lưu trữ của chúng ta có băng thông khả dụng được đo bằng Gigabits, vì vậy tôi không chắc chắn về điều này " khôn ngoan "mà" LOOP = BAD "vẫn được áp dụng.
Geoff Griswald

1

Chỉ While Loop được hỗ trợ chính thức bởi máy chủ SQL. Đã có câu trả lời cho vòng lặp DO while. Tôi đang giải đáp chi tiết về các cách đạt được các loại vòng lặp khác nhau trong máy chủ SQL.

Nếu bạn biết, bạn cần phải hoàn thành lặp đầu tiên của vòng lặp dù sao, sau đó bạn có thể thử do..while hoặc REPEAT..UNTIL phiên bản của SQL server.

DO..WHILE Loop

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

REPEAT..UNTIL Loop

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

Vòng lặp FOR

DECLARE @cnt INT = 0;

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

PRINT 'Done FOR LOOP';

Tài liệu tham khảo


Điều này có vẻ giống như một bản sao-dán-sắp xếp lại từ stackoverflow.com/a/46362450/8239061 .
SecretAgentMan

@SecretAgentMan: Cả hai câu trả lời đều trả lời các câu hỏi khác nhau. Dữ liệu bổ sung được đưa ra trong cả hai câu trả lời.
Somnath Muluk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.