CodeGym /Các khóa học /SQL SELF /Phân tích các lỗi phổ biến khi làm việc với cấu trúc điều...

Phân tích các lỗi phổ biến khi làm việc với cấu trúc điều khiển và logging

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

Trước khi vào phần chính, tụi mình dừng lại chút để nói về những lỗi và thiếu sót hay gặp nhất mà bạn có thể vấp phải. Lỗi trong SQL đúng là nỗi đau của dev, mà thường thì nó lại xuất hiện đúng lúc không mong muốn nhất.

1. Lỗi cú pháp: "quên đóng IF"

Lỗi cú pháp là mấy vấn đề cơ bản nhất, nhưng lại gặp nhiều hơn bạn nghĩ đó. Ví dụ, nếu bạn quên đóng block điều kiện IF bằng END IF;, compiler sẽ chửi bạn ngay.

Ví dụ lỗi:

CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
    IF num > 0 THEN
        RETURN 'Dương';
    ELSE
        RETURN 'Âm';
-- đâu đó bị mất END IF;
END;
$$ LANGUAGE plpgsql;

Khi bạn thử chạy đoạn code này sẽ nhận được lỗi: ERROR: syntax error at or near "END". Tại sao? Vì block IF vẫn còn mở.

Làm sao tránh mấy lỗi này?

Luôn luôn viết code có cấu trúc rõ ràng. Khi mở block (ví dụ IF), viết luôn phần đóng. Đây là ví dụ đã sửa:

CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
    IF num > 0 THEN
        RETURN 'Dương';
    ELSE
        RETURN 'Âm';
    END IF; -- nhớ đóng block nha
END;
$$ LANGUAGE plpgsql;

2. Quên xử lý hết các trường hợp trong CASE: "Nếu không khớp cái nào thì sao?"

Khi dùng CASE, luôn thêm nhánh ELSE để xử lý mấy trường hợp bất ngờ. Không có nhánh này thì có thể trả về NULL ngoài ý muốn.

Ví dụ lỗi:

CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
    RETURN CASE grade
        WHEN 'A' THEN 'Xuất sắc'
        WHEN 'B' THEN 'Tốt'
        WHEN 'C' THEN 'Trung bình'
        -- Nếu grade = 'D' hoặc điểm khác thì sao?
    END;
END;
$$ LANGUAGE plpgsql;

Nếu bạn truyền vào giá trị D, function sẽ trả về NULL, có thể gây lỗi trong code của bạn.

Cách sửa:

CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
    RETURN CASE grade
        WHEN 'A' THEN 'Xuất sắc'
        WHEN 'B' THEN 'Tốt'
        WHEN 'C' THEN 'Trung bình'
        ELSE 'Điểm không xác định' -- Bắt hết các trường hợp còn lại
    END;
END;
$$ LANGUAGE plpgsql;

3. Vấn đề với vòng lặp vô hạn: "Sao server bị treo?"

Dùng vòng lặp LOOP mà quên điều kiện thoát là dễ bị chạy mãi không dừng:

Ví dụ lỗi:

CREATE OR REPLACE FUNCTION infinite_loop_demo()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 1;
BEGIN
    LOOP
        i := i + 1;
        -- Không có điều kiện thoát!
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Code này sẽ làm server bị treo vì vòng lặp không bao giờ kết thúc.

Cách sửa:

Thêm điều kiện thoát bằng EXIT:

CREATE OR REPLACE FUNCTION finite_loop_demo()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 1;
BEGIN
    LOOP
        i := i + 1;
        IF i > 10 THEN
            EXIT; -- Điều kiện thoát
        END IF;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

4. Bỏ qua lượt trong vòng lặp: "Còn dữ liệu bị thiếu thì sao?"

Khi dùng CONTINUE để bỏ qua lượt, nếu không tính hết các trường hợp thì dễ bị lỗi. Ví dụ:

Ví dụ lỗi:

CREATE OR REPLACE FUNCTION skip_even()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 0;
BEGIN
    WHILE i < 10 LOOP
        i := i + 1;
        IF i % 2 = 0 THEN
            CONTINUE; -- Bỏ qua số chẵn luôn
        END IF;
        RAISE NOTICE 'Số lẻ: %', i;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Nếu tất cả số đều là số chẵn thì sao? Server vẫn chạy nhưng bạn sẽ không thấy kết quả gì.

Cách sửa:

Nhớ xử lý dữ liệu cho đúng, thêm log để kiểm soát:

CREATE OR REPLACE FUNCTION skip_even_logging()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 0;
BEGIN
    WHILE i < 10 LOOP
        i := i + 1;
        IF i % 2 = 0 THEN
            RAISE NOTICE 'Bỏ qua số chẵn: %', i;
            CONTINUE;
        END IF;
        RAISE NOTICE 'Số lẻ: %', i;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Giờ thì bạn sẽ thấy số nào bị bỏ qua.

5. Xử lý lỗi sai: "Đâu rồi RAISE EXCEPTION của tui?"

Xử lý lỗi bằng RAISE EXCEPTION rất mạnh, nhưng dễ bị sai cú pháp.

Ví dụ lỗi:

CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
    IF num < 0 THEN
        RAISE 'Không cho phép số âm!';
    END IF;
    RETURN num * num;
END;
$$ LANGUAGE plpgsql;

Code này sẽ báo lỗi vì cú pháp RAISE sai (thiếu mức độ thông báo).

Cách sửa:

CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
    IF num < 0 THEN
        RAISE EXCEPTION 'Không cho phép số âm!';
    END IF;
    RETURN num * num;
END;
$$ LANGUAGE plpgsql;

6. Lỗi khi logging: "Sao lỗi của tui không ghi vào error_log?"

Ghi log vào bảng error_log có thể bị lỗi do sai trong câu lệnh INSERT INTO.

Ví dụ lỗi:

CREATE OR REPLACE FUNCTION log_error(err_msg TEXT)
RETURNS VOID AS $$
BEGIN
    INSERT INTO error_log (error_message, error_time)
    VALUES (err_msg, CURRENT_TIMESTAMP); -- Nếu sai tên cột thì sao?
END;
$$ LANGUAGE plpgsql;

Nếu bảng error_log đổi tên cột (ví dụ thành error_msg), sẽ bị lỗi ngay.

Cách tránh:

Luôn kiểm tra cấu trúc bảng hoặc dùng schema chặt chẽ để quản lý dữ liệu.

7. Sự bất cẩn và "yếu tố con người"

Lỗi không chỉ do kỹ thuật mà còn do bất cẩn. Quên debug, biến không dùng tới hoặc code không format sẽ biến function của bạn thành mớ hỗn độn.

Ví dụ:

DECLARE
    i INTEGER; -- Để làm gì nếu không dùng tới?

Cách sửa: xóa mấy phần code thừa để code sạch và dễ hiểu hơn.

Giờ thì bạn đã sẵn sàng tránh mấy lỗi phổ biến nhất trong PL/pgSQL và viết code vui vẻ hơn rồi đó. Đừng quên test, log và fix bug kịp thời — như vậy bạn sẽ tiết kiệm được khối thời gian và bớt bị khách gọi điện làm phiền!

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Xử lý lỗi
Xử lý lỗi
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION