CodeGym /Các khóa học /SQL SELF /Sử dụng vòng lặp: LOOP, FOR, WHILE trong PL/pgSQL

Sử dụng vòng lặp: LOOP, FOR, WHILE trong PL/pgSQL

SQL SELF
Mức độ , Bài học
Có sẵn

Vòng lặp cho phép chạy một block code nhiều lần liên tiếp, miễn là điều kiện nào đó còn đúng hoặc khi đang lặp qua một tập dữ liệu nào đó. Cực kỳ tiện để tự động hóa task, xử lý dữ liệu lớn hoặc làm mấy thao tác lặp đi lặp lại.

Hãy tưởng tượng bạn phải tự tay phát kẹo cho từng đứa trẻ trong nhóm. Quá là hỗn loạn luôn! Thay vào đó, bạn chỉ cần đi qua danh sách bọn trẻ và phát từng đứa một viên kẹo. Trong trường hợp này, "đi qua danh sách" chính là vòng lặp đó.

PostgreSQL hỗ trợ mấy loại vòng lặp sau:

  1. LOOP — vòng lặp đa năng, chạy cho đến khi bạn tự dừng nó.
  2. FOR — vòng lặp với số lần xác định, lặp qua một dải số hoặc kết quả truy vấn.
  3. WHILE — vòng lặp chạy khi điều kiện còn đúng.

Giờ mình sẽ giải thích từng loại nhé.

Vòng lặp vô hạn: LOOP

LOOP là dạng vòng lặp cơ bản nhất trong PL/pgSQL, cứ lặp mãi block code bên trong. Vòng này chạy vô hạn, bạn phải tự dừng nó bằng lệnh EXIT.

Cú pháp:

LOOP
    -- Code của bạn ở đây
END LOOP;

Lấy ví dụ nhé. Tính tổng các số từ 1 đến 10 bằng LOOP:

DO $$
DECLARE
    counter INT := 1;
    sum INT := 0;
BEGIN
    LOOP
        sum := sum + counter; -- cộng giá trị hiện tại của biến đếm
        counter := counter + 1; -- tăng biến đếm

        -- Kết thúc vòng lặp nếu biến đếm lớn hơn 10
        IF counter > 10 THEN
            EXIT;
        END IF;
    END LOOP;

    RAISE NOTICE 'Tổng các số từ 1 đến 10: %', sum;
END $$;
  1. Biến counter tăng lên mỗi lần lặp.
  2. Điều kiện IF counter > 10 THEN EXIT; sẽ dừng vòng lặp khi biến đếm vượt quá 10.
  3. Cuối cùng sẽ in ra tổng các số.

Vòng lặp qua dải số hoặc tập dữ liệu: FOR

Loại vòng lặp thứ hai, FOR, dùng để lặp qua:

  1. Một dải số.
  2. Kết quả truy vấn SQL.

Vòng lặp qua dải số

Cú pháp:

FOR variable IN [REVERSE] start..end LOOP
    -- Code của bạn ở đây
END LOOP;

In ra các số từ 1 đến 5:

DO $$
BEGIN
    FOR i IN 1..5 LOOP
        RAISE NOTICE 'Giá trị hiện tại: %', i;
    END LOOP;
END $$;

Ví dụ với thứ tự ngược lại:

DO $$
BEGIN
    FOR i IN REVERSE 5..1 LOOP
        RAISE NOTICE 'Thứ tự ngược: %', i;
    END LOOP;
END $$;

Vòng lặp qua kết quả truy vấn SQL

Kiểu này tiện để xử lý từng dòng trong bảng.

Cú pháp:

FOR variable IN QUERY (SELECT ...) LOOP
    -- Code của bạn ở đây
END LOOP;

Lấy ví dụ lặp qua từng dòng trong bảng students:

DO $$
DECLARE
    student_name TEXT;
BEGIN
    FOR student_name IN QUERY (SELECT name FROM students) LOOP
        RAISE NOTICE 'Xin chào, %!', student_name;
    END LOOP;
END $$;

Vòng lặp có điều kiện: WHILE

WHILE sẽ chạy khi điều kiện cho trước còn đúng.

Cú pháp:

WHILE điều_kiện LOOP
    -- Code của bạn ở đây
END LOOP;

Giờ mình tính tổng các số từ 1 đến 10 bằng WHILE nhé:

DO $$
DECLARE
    counter INT := 1;
    sum INT := 0;
BEGIN
    WHILE counter <= 10 LOOP
        sum := sum + counter;
        counter := counter + 1;
    END LOOP;

    RAISE NOTICE 'Tổng các số từ 1 đến 10: %', sum;
END $$;

Ví dụ thực tế

Giờ khi đã hiểu cơ bản về vòng lặp, mình sẽ cho bạn xem vài ví dụ ứng dụng nhé.

Ví dụ 1: tạo bảng cửu chương

DO $$
DECLARE
    i INT;
    j INT;
BEGIN
    FOR i IN 1..5 LOOP
        FOR j IN 1..5 LOOP
            RAISE NOTICE '% x % = %', i, j, i * j;
        END LOOP;
    END LOOP;
END $$;

Ví dụ 2: lặp qua kết quả truy vấn. Giả sử bạn có bảng products với các trường idprice. Cập nhật tất cả giá, tăng lên 10%.

DO $$
DECLARE
    prod RECORD;
BEGIN
    FOR prod IN QUERY (SELECT id, price FROM products) LOOP
        UPDATE products
        SET price = prod.price * 1.1
        WHERE id = prod.id;
    END LOOP;
END $$;

Lỗi thường gặp và cách tránh

Vòng lặp vô hạn trong LOOP hoặc WHILE. Nếu quên thêm điều kiện dừng (EXIT hoặc điều kiện đúng trong WHILE), vòng lặp sẽ chạy mãi không dừng. Kiểu như lái xe mà không có phanh ấy.

Lỗi khi lặp qua kết quả truy vấn. Nếu cấu trúc dữ liệu trả về không đúng như mong đợi, bạn sẽ gặp lỗi trong vòng lặp FOR IN QUERY.

Truy vấn không tối ưu trong vòng lặp. Ví dụ, chạy UPDATE trong mỗi lần lặp có thể làm chậm chương trình rất nhiều. Trong trường hợp này nên dùng một câu SQL duy nhất thay vì vòng lặp.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION