CodeGym /课程 /SQL SELF /插入和更新数据时的错误处理

插入和更新数据时的错误处理

SQL SELF
第 22 级 , 课程 3
可用

咱们来看看往表里插新数据时常见的那些坑。

错误1:试图往必填字段插入NULL

PostgreSQL会很认真地保证你的数据库规则都被遵守。来看几个可能导致报错的约束例子:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL, -- 名字不能为空
    age INT
);

-- 错误:name字段必须填写
INSERT INTO students (name, age) VALUES (NULL, 20);

结果:报错 null value in column "name" of relation "students" violates not-null constraint`

你得注意你加了什么数据。也许这个字段以前能是NULL,现在已经是必填了。

错误2:唯一列里有重复数据。

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    course_name TEXT UNIQUE -- 课程名必须唯一
);

-- 第一次插入没问题
INSERT INTO courses (course_name) VALUES ('SQL Basics');

-- 第二次插入会报错
INSERT INTO courses (course_name) VALUES ('SQL Basics');

结果:报错 duplicate key value violates unique constraint`

通常这不是你的锅,是用户手滑重复点了某个操作。这种情况其实不用管。

错误3:外键约束被破坏。

CREATE TABLE enrollments (
    enrollment_id SERIAL PRIMARY KEY,
    student_id INT REFERENCES students(id), -- 必须有这个ID的学生
    course_id INT REFERENCES courses(course_id)
);

-- 错误:ID=99的学生不存在
INSERT INTO enrollments (student_id, course_id) VALUES (99, 1);

结果:报错 insert or update on table "enrollments" violates foreign key constraint`

其实报错是好事。数据完整性被破坏才是最糟糕的。大概率是你代码有bug,或者数据过时了。总之数据库没让你破坏它的完整性,这就很棒。

PostgreSQL里的错误处理

没错,错误总会发生。但关键不是发现它,而是会怎么处理它。

事务:数据保护神器

操作数据时我们经常用事务来保证数据一致性。如果出错了,可以回滚所有更改。

例子:往两张表里加数据。

BEGIN; -- 开始事务

-- 往students表插数据
INSERT INTO students (name, age) VALUES ('Otto Lin', 21);

-- 往enrollments表插记录
-- 如果ID=10的课程不存在,这里会报错
INSERT INTO enrollments (student_id, course_id) VALUES (1, 10);

-- 如果一切顺利
COMMIT;
-- 如果出错了,"撤销"所有更改
ROLLBACK;

如果course_id = 10的课程不存在,students表里的插入也会被撤销。

事务里的错误处理

在PostgreSQL里你可以预判错误并直接在SQL里用EXCEPTION块处理。

例子:加学生并让他选课。如果出错,把错误写进日志。

DO $$
BEGIN
    -- 试着插入数据
    INSERT INTO students (name, age) VALUES ('Anna Song', 22);
    INSERT INTO enrollments (student_id, course_id) VALUES (2, 999); -- 报错

    -- 如果都成功
    RAISE NOTICE '记录添加成功!';
EXCEPTION
    WHEN foreign_key_violation THEN
        -- 处理外键冲突
        RAISE WARNING '指定的course_id课程不存在。';
END $$;

ON CONFLICT检查唯一性

你可以提前用ON CONFLICT语法防止UNIQUE约束冲突。这样可以指定遇到冲突时怎么处理。

例子:如果插入重复课程就跳过。

INSERT INTO courses (course_name)
    VALUES ('SQL Basics')
ON CONFLICT (course_name) DO NOTHING; -- 跳过重复数据

或者直接更新已有行:

INSERT INTO courses (course_name)
    VALUES ('SQL Basics')
ON CONFLICT (course_name) DO UPDATE     
    SET course_name = EXCLUDED.course_name || ' (Updated)';

关于ON CONFLICT操作符的更多内容我会在下一级讲,等我们聊批量数据导入的时候 :P

常见数据操作错误及预防

你已经看到,主要的错误来源有:

  1. 违反约束(NOT NULLUNIQUEFOREIGN KEY)。
  2. 更新或删除数据时没加条件(WHERE)。
  3. 事务执行顺序出错。

想保护自己:

  • 大操作用事务和ROLLBACK兜底。
  • 插入前一定要检查数据。
  • 把错误都写日志,方便分析。
  • ON CONFLICT避免重复记录。

现在你已经有了对抗错误的武器!记住:好程序员不是不犯错,而是会修错。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION