CodeGym /课程 /SQL SELF /操作数据时的常见错误

操作数据时的常见错误

SQL SELF
第 22 级, 课程 4
可用

用数据库就像程序员的生活一样:充满了意外。就算是老司机开发者也可能犯错,比如不小心删了数据、插入了重复值,或者违反了完整性约束。关键不是只会躲坑,更要知道如果踩坑了怎么补救。来,咱们看看几个最典型的错误。

错误1:漏写 WHERE 条件

最经典的错误,初学者(其实老司机偶尔也会)经常犯的,就是在更新或删除数据的SQL里忘了加 WHERE。没有 WHERE 的SQL会把整张表的所有行都更新或删除。

-- 千万别这样写:
UPDATE students SET status = '已毕业';

-- 或者这样:
DELETE FROM students;

后果:想象一下,执行完这种SQL后,你发现 students 这张存着所有学生信息的表直接空了。最糟糕的是——如果你没有备份或者没用事务,这些数据就真的回不来了(就算有事务也够你喝一壶的)。

怎么避免:每次写 UPDATE 和 DELETE 时都要加条件,明确指定你要改或删哪几行。

-- 正确写法:
UPDATE students
SET status = '已毕业'
WHERE year_of_study = 4;

DELETE FROM students
WHERE status = '已开除';

还有个小技巧——删数据前先用 SELECT 检查下条件对不对:

-- 先查查:
SELECT * FROM students WHERE status = '已开除';

-- 再删:
DELETE FROM students WHERE status = '已开除';

错误2:违反唯一性约束(UNIQUE)

如果表上有 UNIQUE 约束,插入重复值就会报错。

-- 因为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');

错误信息:

ERROR: duplicate key value violates unique constraint "students_email_key"

怎么避免:插入前先查查有没有同样的值。

-- 一种做法:
SELECT * FROM students WHERE email = 'otto.lin@email.com';

-- 或者用UPSERT写法:
INSERT INTO students (name, email)
VALUES ('Peter Pen', 'otto.lin@email.com')
ON CONFLICT (email) DO NOTHING;

错误3:违反完整性约束(FOREIGN KEY)

假设你有两张表:students 和 enrollments,enrollments 里的 student_id 是外键,关联 students 的 id。如果你往 enrollments 插入一个 student_id,但 students 里根本没有这个id,就会报错。

INSERT INTO enrollments (student_id, course_id)
VALUES (999, 101); -- 报错,因为student_id 999不存在

怎么避免?

  1. 插入到关联表前,先查查主表里有没有这条记录:
SELECT * FROM students WHERE id = 999;
  1. 可以用 ON DELETE CASCADE 约束,这样主表删了数据,关联表的记录也会自动删(不过要小心用)。
CREATE TABLE enrollments (
    id SERIAL PRIMARY KEY,
    student_id INT REFERENCES students(id) ON DELETE CASCADE,
    course_id INT
);

错误4:数据类型不对

插入或更新数据时,PostgreSQL会严格检查类型。如果你往数字字段塞字符串,肯定报错。

-- 类型不匹配报错:
INSERT INTO students (id, name) VALUES ('abc', 'Alex Go');

错误信息:

ERROR: invalid input syntax for type integer

怎么避免?注意插入的数据类型。如果数据来自用户表单,记得在应用层先校验。

错误5:并发访问问题(数据泄露)

想象一下,两个用户同时改同一条记录。如果没有合适的事务隔离,很容易冲突。

-- 用户A:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 用户B:
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 1;

怎么避免?用事务和隔离级别,防止数据被同时改。

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

错误6:用 TRUNCATE 导致数据丢失

TRUNCATE 会把表里所有行都删光,没法恢复,因为这个命令不支持 ROLLBACK(不会触发触发器,执行也很快)。

-- 全部删光,无法恢复:
TRUNCATE TABLE students;

怎么避免:如果想保留回滚的可能,用带条件的 DELETE 代替 TRUNCATE。

BEGIN;
DELETE FROM students WHERE year_of_study = 1;
-- 如果后悔了:
ROLLBACK;

错误7:重要操作没用事务

如果一个复杂操作分好几步,中间某一步出错,数据可能就不一致了。

-- 第一步:加学生
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');

-- 第二步:给他选课
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101); -- 报错

怎么避免?把这些操作包进事务里:

BEGIN;

INSERT INTO students (name, email) VALUES ('伊万 伊万诺夫', 'ivan.ivanov@email.com');
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101);

COMMIT;

如果中间有任何一步出错,你可以回滚:

ROLLBACK;

错误8:随意对 NULL 操作

NULL 经常让人翻车,因为它既不是0,也不是空字符串,跟它比较可能会有意外结果。

-- 这样查不到:
SELECT * FROM students WHERE email = NULL;

怎么避免?用 IS NULL 或 IS NOT NULL:

SELECT * FROM students WHERE email IS NULL;

这些常见错误谁都难免,但只要你知道怎么发现和避免它们,操作数据就能又安全又高效。PostgreSQL 虽然严格,但它是你数据的靠谱守护者,出错时总会给你提示。记住,错误不是敌人,而是老师。

2
任务
SQL SELF, 第 22 级, 课程 4
已锁定
防止删除所有数据
防止删除所有数据
1
调查/小测验
事务入门第 22 级,课程 4
不可用
事务入门
事务入门
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION