PostgreSQL 约束延迟触发

PG只支持以下几种约束延迟触发(并不是不触发,而是再事务结束的时候触发)

UNIQUEPRIMARY KEYREFERENCES(外键)和 EXCLUDE

测试例子:

sql 复制代码
CREATE TABLE logs (
    id INTEGER,
    log_time TIMESTAMP,
    message TEXT,
    CONSTRAINT pk_logs 
        PRIMARY KEY (id) 
        DEFERRABLE
);

BEGIN;
SET CONSTRAINTS pk_logs DEFERRED;

-- 可以暂时插入重复ID,最后再修复
INSERT INTO logs (id, log_time, message) VALUES
(1, '2024-01-01 10:00:00', 'Message 1'),
(1, '2024-01-01 10:01:00', 'Message 2'), -- 暂时允许重复
(2, '2024-01-01 10:02:00', 'Message 3');

-- 修复重复的ID
UPDATE logs SET id = 3 WHERE id = 1 AND message = 'Message 2';

COMMIT;  -- 提交时才检查主键唯一性


建表的时候指定DEFERRABLE是可以延迟的意思,是延迟的前提条件,默认是 INITIALLY IMMEDIATE

这时候需要在开始事务之后使用
SET CONSTRAINTS DEFERRED语句来确定是否要真的延迟

当然也可以指定INITIALLY DEFERRED 这样在事务中就不需要执行
SET CONSTRAINTS DEFERRED 语句了

如下图所测试

指定INITIALLY DEFERRED

sql 复制代码
CREATE TABLE logs (
    id INTEGER,
    log_time TIMESTAMP,
    message TEXT,
    CONSTRAINT pk_logs 
        PRIMARY KEY (id) 
        DEFERRABLE INITIALLY DEFERRED
);

begin;

INSERT INTO logs (id, log_time, message) VALUES
(1, '2024-01-01 10:00:00', 'Message 1'),
(1, '2024-01-01 10:01:00', 'Message 2'), 
(2, '2024-01-01 10:02:00', 'Message 3');

-- 修复重复的ID
UPDATE logs SET id = 3 WHERE id = 1 AND message = 'Message 2';

COMMIT;  -- 提交时才检查主键唯一性

修改约束

当然也可以修改约束延迟模式

但是需要先删除掉约束,重建的时候指定

sql 复制代码
postgres=# alter table logs drop constraint pk_logs;
ALTER TABLE
postgres=# alter table logs add constraint pk_logs primary key(id) deferrable initially deferred;
ALTER TABLE

当然oracle和达梦默认就是延迟模式

如下所示:

sql 复制代码
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.18.0.0.0

SQL> create table tab(id numeric primary key);

Table created.

SQL> insert into tab values (1);

1 row created.

SQL> insert into tab values(2);

1 row created.

SQL> commit;

Commit complete.

SQL> update tab set id=id+1;

2 rows updated.

SQL> commit;

Commit complete.

SQL>

达梦

sql 复制代码
SQL> create table tab(id int);
executed successfully
used time: 4.234(ms). Execute id is 1702.
SQL> alter table tab add constraint tab_pkey primary key(id);
executed successfully
used time: 12.044(ms). Execute id is 1703.
SQL> insert into tab values (1),(2);
affect rows 2

used time: 1.255(ms). Execute id is 1704.
SQL> commit;
executed successfully
used time: 1.605(ms). Execute id is 1705.
SQL> select * from v$version;

LINEID     BANNER
---------- ---------------------------------
1          DM Database Server 64 V8
2          DB Version: 0x7000c
3          03134284194-20240703-234060-20108
4          Msg Version: 12
5          Gsu level(5) cnt: 0

used time: 0.336(ms). Execute id is 1706.
SQL> update tab set id=id+1;
affect rows 2

used time: 1.135(ms). Execute id is 1707.
SQL> commit;
executed successfully
used time: 1.596(ms). Execute id is 1708.
SQL>
相关推荐
全栈老石41 分钟前
拆解低代码引擎核心:元数据驱动的"万能表"架构
数据库·低代码
倔强的石头_19 小时前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou642 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤3 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
爱可生开源社区4 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1774 天前
《从零搭建NestJS项目》
数据库·typescript
加号35 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏5 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐5 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
百锦再5 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip