CodeGym /Các khóa học /SQL SELF /Những lỗi thường gặp khi làm việc với dữ liệu

Những lỗi thường gặp khi làm việc với dữ liệu

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

Làm việc với database cũng giống như cuộc sống của coder: đầy bất ngờ. Ngay cả dev kỳ cựu cũng có thể mắc lỗi, như xóa nhầm dữ liệu, cố gắng insert trùng lặp hoặc vi phạm constraint về toàn vẹn. Nhưng quan trọng không chỉ là tránh lỗi, mà còn phải biết cách sửa nếu lỡ dính phải. Cùng xem qua vài lỗi điển hình nhất nhé.

Lỗi số 1: Thiếu điều kiện WHERE

Lỗi kinh điển mà newbie hay dính (và, nói thật là, đôi khi cả dev lâu năm cũng vậy), là quên thêm WHERE vào câu lệnh update hoặc delete. Query không có WHERE sẽ update hoặc xóa tất cả các dòng trong bảng.

-- Ví dụ không nên làm:
UPDATE students SET status = 'tot nghiep';

-- Hoặc như này:
DELETE FROM students;

Hậu quả: tưởng tượng sau khi chạy xong query này bạn phát hiện bảng students chứa toàn bộ dữ liệu sinh viên đã trống trơn. Và điều tệ nhất là — không thể lấy lại dữ liệu nếu không có backup hoặc không dùng transaction (và kể cả có thì cũng stress lắm rồi).

Cách tránh: luôn thêm điều kiện vào query UPDATEDELETE để xác định chính xác dòng nào bạn muốn sửa hoặc xóa.

-- Làm như này mới đúng:
UPDATE students
SET status = 'tot nghiep'
WHERE year_of_study = 4;

DELETE FROM students
WHERE status = 'da duoi hoc';

Một mẹo nữa — trước khi xóa, luôn chạy SELECT để kiểm tra điều kiện đã đúng chưa:

-- Kiểm tra trước:
SELECT * FROM students WHERE status = 'da duoi hoc';

-- Sau đó mới xóa:
DELETE FROM students WHERE status = 'da duoi hoc';

Lỗi số 2: Vi phạm tính duy nhất của dữ liệu (UNIQUE)

Nếu bảng có constraint UNIQUE, thì cố gắng insert trùng sẽ bị lỗi ngay.

-- Lỗi do trùng email:
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');
INSERT INTO students (name, email) VALUES ('Peter Pen', 'otto.lin@email.com');

Lỗi:

ERROR: duplicate key value violates unique constraint "students_email_key"

Cách tránh: trước khi insert, nên kiểm tra xem đã có dòng nào có giá trị đó chưa.

-- Một cách làm:
SELECT * FROM students WHERE email = 'otto.lin@email.com';

-- Hoặc dùng UPSERT:
INSERT INTO students (name, email)
VALUES ('Peter Pen', 'otto.lin@email.com')
ON CONFLICT (email) DO NOTHING;

Lỗi số 3: Vi phạm constraint toàn vẹn (FOREIGN KEY)

Giả sử bạn có hai bảng: studentsenrollments, trong đó student_id ở bảng enrollments là foreign key liên kết với id của bảng students. Nếu bạn cố insert một dòng vào enrollments với student_id không tồn tại trong students, sẽ bị lỗi ngay.

INSERT INTO enrollments (student_id, course_id)
VALUES (999, 101); -- Lỗi vì student_id 999 không tồn tại

Làm sao tránh?

  1. Luôn kiểm tra xem dòng có tồn tại ở bảng cha trước khi insert vào bảng liên kết:
SELECT * FROM students WHERE id = 999;
  1. Dùng constraint ON DELETE CASCADE để khi xóa dòng ở bảng cha thì dòng liên kết cũng tự động bị xóa (nhưng nhớ cẩn thận nhé).
CREATE TABLE enrollments (
    id SERIAL PRIMARY KEY,
    student_id INT REFERENCES students(id) ON DELETE CASCADE,
    course_id INT
);

Lỗi số 4: Kiểu dữ liệu sai

Khi insert hoặc update, PostgreSQL kiểm tra rất kỹ kiểu dữ liệu. Nếu bạn cố insert chuỗi vào trường số, sẽ bị lỗi ngay.

-- Lỗi do kiểu dữ liệu không hợp lệ:
INSERT INTO students (id, name) VALUES ('abc', 'Alex Go');

Lỗi:

ERROR: invalid input syntax for type integer

Cách tránh? Luôn chú ý kiểu dữ liệu khi insert. Nếu dữ liệu đến từ form người dùng, nhớ validate ở phía app nhé.

Lỗi số 5: Vấn đề truy cập song song (rò rỉ dữ liệu)

Hãy tưởng tượng hai người dùng cùng lúc update một dòng trong bảng. Nếu không có isolation cho transaction, rất dễ bị conflict.

-- Người dùng A:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- Người dùng B:
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 1;

Cách tránh? Dùng transaction và isolation level để ngăn việc thay đổi dữ liệu cùng lúc.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

Lỗi số 6: Mất dữ liệu do TRUNCATE

TRUNCATE xóa sạch mọi dòng trong bảng mà không thể khôi phục, vì lệnh này không hỗ trợ ROLLBACK (không gọi trigger và thực thi cực nhanh).

-- Xóa sạch không thể hoàn tác:
TRUNCATE TABLE students;

Cách tránh: dùng DELETE có điều kiện thay vì TRUNCATE nếu muốn có thể rollback.

BEGIN;
DELETE FROM students WHERE year_of_study = 1;
-- Nếu đổi ý:
ROLLBACK;

Lỗi số 7: Không dùng transaction cho thao tác quan trọng

Nếu thực hiện thao tác phức tạp gồm nhiều bước, mà giữa chừng bị lỗi, dữ liệu có thể bị mất nhất quán.

-- Bước 1: thêm sinh viên
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');

-- Bước 2: ghi danh vào khóa học
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101); -- lỗi

Cách tránh? Gói các thao tác này vào transaction:

BEGIN;

INSERT INTO students (name, email) VALUES ('Ivan Ivanov', 'ivan.ivanov@email.com');
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101);

COMMIT;

Nếu có lỗi ở bất kỳ bước nào, bạn có thể rollback lại:

ROLLBACK;

Lỗi số 8: Làm việc với NULL không cẩn thận

NULL thường gây bất ngờ, vì nó không bằng 0, cũng không phải chuỗi rỗng, và so sánh với nó có thể ra kết quả không ngờ.

-- Cái này sẽ không chạy:
SELECT * FROM students WHERE email = NULL;

Cách tránh? Dùng IS NULL hoặc IS NOT NULL:

SELECT * FROM students WHERE email IS NULL;

Lỗi phổ biến là điều không tránh khỏi, nhưng nếu biết nhận diện và phòng tránh, bạn sẽ thao tác dữ liệu an toàn và hiệu quả hơn. PostgreSQL — nghiêm khắc nhưng công bằng, luôn sẵn sàng trả về lỗi nếu có gì sai. Nhớ nhé, lỗi không phải kẻ thù, mà là thầy dạy của bạn.

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Giới thiệu về giao dịch
Giới thiệu về giao dịch
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION