当前位置: 首页 > news >正文

PostgreSQL 范围、空间唯一性约束

PostgreSQL 范围、空间唯一性约束

在 PostgreSQL 中,实现数据唯一性不仅限于 UNIQUEPRIMARY KEY,还可以使用 EXCLUDE 约束配合 GiST 索引来实现更灵活的唯一性检查。


1. UNIQUE 约束

作用

  • 保证某列(或多列组合)的值在表中不重复。
  • 可以有多个 UNIQUE 约束。
  • 允许列中出现多个 NULL(因为 NULL 被认为是“未知”,彼此不相等)。

测试语句

DROP TABLE IF EXISTS customers;postgres=# CREATE TABLE customers (
postgres(#     customerid INT UNIQUE,
postgres(#     name TEXT
postgres(# );
CREATE TABLE
postgres=# 
postgres=# -- 插入测试数据
postgres=# INSERT INTO customers VALUES (1, 'Alice'); -- 成功
INSERT 0 1
postgres=# INSERT INTO customers VALUES (2, 'Bob');   -- 成功
INSERT 0 1
postgres=# INSERT INTO customers VALUES (1, 'Charlie'); -- 报错:违反唯一约束
ERROR:  duplicate key value violates unique constraint "customers_customerid_key"
DETAIL:  Key (customerid)=(1) already exists.
postgres=# 
postgres=# -- NULL 测试
postgres=# INSERT INTO customers VALUES (NULL, 'David'); -- 成功
INSERT 0 1
postgres=# INSERT INTO customers VALUES (NULL, 'Eve');   -- 成功(UNIQUE 允许多个 NULL)

特点总结
可在同一个表中定义多个。可接受多个 NULL。自动创建唯一 B-Tree 索引。

2. PRIMARY KEY 约束

作用
唯一标识表中每一行数据。每个表只能有一个 PRIMARY KEY。自动包含 NOT NULL 和唯一性约束。
测试语句

DROP TABLE IF EXISTS customers_pk;
postgres=# CREATE TABLE customers_pk (
postgres(#     customerid INT PRIMARY KEY,
postgres(#     name TEXT
postgres(# );
CREATE TABLE
postgres=# -- 插入测试数据
postgres=# INSERT INTO customers_pk VALUES (1, 'Alice'); -- 成功
INSERT 0 1
postgres=# INSERT INTO customers_pk VALUES (2, 'Bob');   -- 成功
INSERT 0 1
postgres=# INSERT INTO customers_pk VALUES (1, 'Charlie'); -- 报错:违反主键唯一性
ERROR:  duplicate key value violates unique constraint "customers_pk_pkey"
DETAIL:  Key (customerid)=(1) already exists.
postgres=# -- NULL 测试
postgres=# INSERT INTO customers_pk VALUES (NULL, 'David');
ERROR:  null value in column "customerid" of relation "customers_pk" violates not-null constraint
DETAIL:  Failing row contains (null, David).
-- 报错:主键列不允许 NULL

特点总结
每表只能有一个主键,可由一列或多列组合。自动 NOT NULL。自动创建唯一 B-Tree 索引。

3. EXCLUDE USING gist

作用
用 GiST 索引实现更灵活的唯一性检查,不仅能比较相等,还能比较空间重叠、范围重叠等复杂条件。常见于几何类型(point、box)、范围类型(int4range、tsrange 等)。

几何类型示例
postgres=# CREATE TABLE boxes (
postgres(#     id SERIAL PRIMARY KEY,
postgres(#     position box,
postgres(#     EXCLUDE USING gist (position WITH &&)
postgres(# );
CREATE TABLE
postgres=# 
postgres=# -- 插入测试数据
postgres=# INSERT INTO boxes (position) VALUES (box(point(0,0), point(1,1))); -- 成功
INSERT 0 1
postgres=# INSERT INTO boxes (position) VALUES (box(point(2,2), point(3,3))); -- 成功
INSERT 0 1
postgres=# INSERT INTO boxes (position) VALUES (box(point(0.5,0.5), point(1.5,1.5)));
ERROR:  conflicting key value violates exclusion constraint "boxes_position_excl"
DETAIL:  Key ("position")=((1.5,1.5),(0.5,0.5)) conflicts with existing key ("position")=((1,1),(0,0)).
-- 报错:两个矩形重叠
时间区间冲突检测示例

假设我们要做一个 会议室预约系统,要求同一个会议室不能在同一时间段被重复预约。我们可以用 EXCLUDE USING gist 来做时间范围的唯一性约束。满足以下三点要求
1、同一会议室 + confirmed 状态 → 不能有时间交叉。
2、不同会议室 → 不受影响。
3、status 不是 confirmed → 不受影响。

-- 1) GiST 索引支持等值比较
CREATE EXTENSION IF NOT EXISTS btree_gist;  --GiST 索引默认能处理几何类型、范围类型的操作符(如 &&),本范例中加入= 的比较,所以增加btree_gist插件辅助。-- 2) 表结构
drop  table if exists reservations;
CREATE TABLE reservations (id serial PRIMARY KEY,room text NOT NULL,during tstzrange NOT NULL,status text NOT NULL DEFAULT 'pending',-- 同一 room 在 status='confirmed' 时,不允许 during 区间重叠CONSTRAINT no_overlap_confirmedEXCLUDE USING gist (room WITH =,   -- 同一个会议室during WITH &&   -- 时间范围有重叠)WHERE (status = 'confirmed')
);postgres=# -- ✅ 成功:第一次预约,会议室 A
postgres=# INSERT INTO reservations (room, during, status)
postgres-# VALUES ('A', '[2025-08-12 09:00,2025-08-12 10:00)', 'confirmed');
INSERT 0 1
postgres=# -- ❌ 失败:同一会议室 A,时间区间有交叉
postgres=# INSERT INTO reservations (room, during, status)
postgres-# VALUES ('A', '[2025-08-12 09:30,2025-08-12 10:30)', 'confirmed');
ERROR:  conflicting key value violates exclusion constraint "no_overlap_confirmed"
DETAIL:  Key (room, during)=(A, ["2025-08-12 09:30:00+08","2025-08-12 10:30:00+08")) conflicts with existing key (room, during)=(A, ["2025-08-12 09:00:00+08","2025-08-12 10:00:00+08"))
postgres=# INSERT INTO reservations (room, during, status)
postgres-# VALUES ('A', '[2025-08-12 10:00,2025-08-12 11:00)', 'confirmed');INSERT 0 1
postgres=# 
postgres=# -- ✅ 成功:会议室 B,即使时间重叠也没问题
postgres=# INSERT INTO reservations (room, during, status)
postgres-# VALUES ('B', '[2025-08-12 09:30,2025-08-12 10:30)', 'confirmed');
INSERT 0 1
postgres=# 
postgres=# -- ✅ 成功:会议室 A,但 status 不是 confirmed,不受限制
postgres=# INSERT INTO reservations (room, during, status)
postgres-# VALUES ('A', '[2025-08-12 09:30,2025-08-12 10:30)', 'pending');
INSERT 0 1

小结
UNIQUE:适合需要唯一性但允许多个 NULL 的列。
PRIMARY KEY:适合作为表的主标识,不允许 NULL,只能有一个。
EXCLUDE USING gist:适合范围/空间/时间等需要复杂冲突检测的场景,比唯一约束灵活。

http://www.dtcms.com/a/327205.html

相关文章:

  • 「ECG信号处理——(23)基于ECG和PPG信号的血压预测」2025年8月12日
  • SQL 生成日期与产品的所有组合:CROSS JOIN(笛卡尔积)
  • Linux 系统运维、网络、SQL Server常用命令
  • 机器学习 [白板推导](九)[变分推断]
  • DRAM、SRAM、NAND Flash、NOR Flash、EEPROM、MRAM存储器你分得清吗?
  • 用pom文件从nexus3拉依赖,无法拉取的一个问题
  • 逻辑删除 vs 物理删除:MyBatis-Plus 实现指南与实践
  • 可泛化逻辑推理Python编程作为医疗AI发展方向研究
  • 关于数据库的restful api接口工具SqlRest的使用
  • 如何在 Ubuntu 24.04 LTS Linux 中安装 JSON Server
  • 2025年国赛新规解读:8-12最新发布文件
  • 初识数据结构——优先级队列(堆!堆!堆!)
  • 偶遇冰狐智能辅助的录音
  • Python初学者笔记第二十四期 -- (面向对象编程)
  • 教程 | 用Parasoft SOAtest实现高效CI回归测试
  • 从零到一的 Python CI/CD 实战指南:用 GitHub Actions 与 Jenkins 打造稳定、可持续交付的工程力
  • 下一代防火墙技术
  • 【ad-hoc 最小生成树 构造】P8957 「CGOI-3」巫泡弹弹乐|普及+
  • 【Redis在智能健身镜中的作用:运动指导与用户数据同步】
  • 计算机网络摘星题库800题笔记 第6章 应用层
  • 使用正则中的sub实现获取我们匹配的字符串,然后追加指定字符
  • 计算机网络---防火墙(Firewall)
  • pyside控件_左右范围滑动控件
  • 深层神经网络
  • torch.max() 函数使用
  • uv 配置和简单使用
  • 6深度学习Pytorch-神经网络--过拟合欠拟合问题解决(Dropout、正则化、早停法、数据增强)、批量标准化
  • OpenHarmony编译与烧录
  • 【完美解决】在 Ubuntu 24.04 上为小米 CyberDog 2 刷机/交叉编译:终极 Docker 环境搭建指南
  • 【LeetCode】2. 两数相加