PostgreSQL 逻辑删除的表的唯一约束的控制

    很多时候,当我们的数据很重要,删除采用的是逻辑删除,仅仅是在记录上指定一个删除标记;这个时候,我们又需要该表的某一字段唯一(未删除的保持唯一,已经有删除标记的行不管),仅仅是采用数据库本身的check unique就不行了。

   现在开始讲一种解决方案:

1. 建表 

postgres=# create table person(id serial,name character varying,delete_flag integer not null default 0);
2. 查看表结构
postgres=# \d person
                                 Table "public.person"
   Column    |       Type        |                      Modifiers                     
-------------+-------------------+----------------------------------------------
 id          | integer           | not null default nextval('person_id_seq'::regclass)
 name        | character varying | 
 delete_flag | integer           | not null default 0
3. 创建function
CREATE OR REPLACE FUNCTION check_person_name_unique( p_name character varying, flag integer)
  RETURNS boolean AS
$BODY$
declare
	count integer:=0;
begin 
	if(flag=1) then
		return true; 
	end if;
	select count(0) from person where name=p_name and delete_flag=0 into count;
	if count>0 then
		return false;
	elseif count=0 then
		return true;
	end if;
end;
  $BODY$
  LANGUAGE plpgsql VOLATILE;
4. 应用到表上
postgres=# alter table person add CONSTRAINT check_unique CHECK (check_person_name_unique(name, delete_flag));
5. 插入测试数据
postgres=# insert into person(name) values('zhangsan');
INSERT 0 1
postgres=# insert into person(name) values('zhangsan');
ERROR:  new row for relation "person" violates check constraint "check_unique"
DETAIL:  Failing row contains (2, zhangsan, 0).
插入两条相同的违反了唯一约束
6. 现在把记录更新 delete_flag=1;
postgres=# select * from person;
 id |   name   | delete_flag 
----+----------+-------------
  1 | zhangsan |           0
(1 row)
postgres=# update person person set delete_flag=1;
UPDATE 1
postgres=# select * from person;
 id |   name   | delete_flag 
----+----------+-------------
  1 | zhangsan |           1
(1 row)
7. 再插入名字相同的 
postgres=# insert into person(name) values('zhangsan');
INSERT 0 1
插入成功
8. 查看数据
postgres=# select * from person;
 id |   name   | delete_flag 
----+----------+-------------
  1 | zhangsan |           1
  3 | zhangsan |           0
(2 rows)

这样就可以保证逻辑删除的记录的唯一性。

<think>嗯,用户现在想了解在PostgreSQL中创建时可以使用的约束条件列。根据用户提供的引用内容,我需要先整理出相关的约束条件,并确保引用正确的参考资料。 首先,引用[2]提到了唯一约束(UNIQUE)、非空约束(NOT NULL)、检查约束(CHECK)和排除约束(EXCLUSION)。这些是常见的约束类型。然后,引用[1]虽然主要讲的创建和管理,但可能包含主键约束(PRIMARY KEY)的信息,因为主键通常是定义的一部分。另外,引用[3]提到触发器中的IF判断,这可能与检查约束或触发器的使用有关,但用户的问题是关于创建时的约束,所以触发器可能属于高级应用,不是基本约束条件。 用户的上一次问题涉及创建同步任务的全流程,其中提到了数据一致性和冲突解决策略。这可能与约束条件有关,比如外键约束确保引用完整性,或者在同步数据时使用唯一约束避免重复。因此,在回答中需要覆盖这些点,并联系实际应用场景。 接下来,我需要列出PostgreSQL支持的约束条件,并为每个约束提供示例和说明。确保每个约束都有对应的引用支持。例如,主键和唯一约束在引用[2]中有例子,检查约束和排除约束也在引用[2]中被提及。非空约束同样在引用[2]的示例中出现。外键约束虽然未在提供的引用中直接提到,但作为常见的约束类型,应该包含在内,可能引用[1]中的管理部分间接支持。 需要注意用户可能混淆触发器和约束,但根据问题,应明确区分。触发器属于更复杂的逻辑,而约束是结构定义的一部分。因此,在回答中要明确约束条件列,并指出触发器是另一种数据完整性机制,但不在本次讨论范围内。 最后,生成相关问题时要结合用户之前的同步任务流程,例如如何利用约束确保数据一致性,或者在同步过程中如何处理约束冲突。这样能帮助用户将约束条件应用到实际场景中,符合他们之前的兴趣点。</think>#### PostgreSQL 创建支持的约束条件列 PostgreSQL 提供多种约束条件来确保数据完整性,以下是核心约束条件及其应用场景: --- ### 1. **主键约束(PRIMARY KEY)** - **作用**:唯一标识中的每一行,自动包含非空(`NOT NULL`)和唯一性(`UNIQUE`)特性。 - **语法示例**: ```sql CREATE TABLE products ( product_id INT PRIMARY KEY, -- 单列主键 product_name VARCHAR(100) ); ``` **或复合主键**: ```sql CREATE TABLE orders ( order_id INT, product_id INT, PRIMARY KEY (order_id, product_id) -- 多列联合主键 ); ``` - **引用支持**:主键约束在定义中常见[^1][^2]。 --- ### 2. **唯一约束(UNIQUE)** - **作用**:确保列(或列组合)的值唯一,但允许空值(`NULL`)。 - **语法示例**: ```sql CREATE TABLE users ( user_id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE -- 单列唯一约束 ); ``` **或通过修改添加**(如引用[2]所示): ```sql ALTER TABLE products ADD CONSTRAINT products_unique_constraint UNIQUE (price); ``` - **应用场景**:防止重复数据(如用户邮箱)[^2]。 --- ### 3. **非空约束(NOT NULL)** - **作用**:强制列不允许空值。 - **语法示例**: ```sql CREATE TABLE employees ( employee_id INT PRIMARY KEY, name VARCHAR(100) NOT NULL, -- 非空约束 hire_date DATE NOT NULL ); ``` - **引用示例**:在引用[2]的`products`中,`product_id`和`product_name`均被定义为`NOT NULL`[^2]。 --- ### 4. **检查约束(CHECK)** - **作用**:定义列值的业务规则,限制取值范围。 - **语法示例**: ```sql CREATE TABLE students ( student_id INT PRIMARY KEY, age INT CHECK (age >= 18), -- 单列检查 grade VARCHAR(10), CONSTRAINT valid_grade CHECK (grade IN ('A', 'B', 'C', 'D')) ); ``` - **高级用法**:支持多列联合检查,例如: ```sql CHECK (start_date < end_date) -- 日期范围有效性验证 ``` - **引用关联**:检查约束在数据完整性规则中起关键作用[^2]。 --- ### 5. **外键约束(FOREIGN KEY)** - **作用**:维护间的引用完整性,确保外键值存在于主的主键中。 - **语法示例**: ```sql CREATE TABLE orders ( order_id INT PRIMARY KEY, product_id INT REFERENCES products(product_id), -- 外键约束 quantity INT ); ``` - **级联操作**: ```sql REFERENCES products(product_id) ON DELETE CASCADE -- 主删除时级联删除记录 ``` --- ### 6. **排除约束(EXCLUSION)** - **作用**:通过自定义运算符避免多行数据满足特定条件,常用于复杂唯一性场景(如时间范围不重叠)。 - **语法示例**: ```sql CREATE TABLE reservations ( room_id INT, reservation_daterange DATERANGE, EXCLUDE USING gist (room_id WITH =, reservation_daterange WITH &&) ); ``` **解释**:禁止同一房间(`room_id`)在时间范围(`reservation_daterange`)上重叠。 - **引用支持**:排除约束在引用[2]中提及,适用于高级数据冲突避免[^2]。 --- ### 7. **默认值(DEFAULT)** - **作用**:为列指定默认值,当插入数据未显式赋值时生效。 - **语法示例**: ```sql CREATE TABLE logs ( log_id SERIAL PRIMARY KEY, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 自动填充时间戳 ); ``` --- ### 约束管理操作 | 操作类型 | 语法示例 | |-----------------|--------------------------------------------------------------------------| | 添加约束 | `ALTER TABLE table_name ADD CONSTRAINT constraint_name CHECK (condition);` | | 删除约束 | `ALTER TABLE table_name DROP CONSTRAINT constraint_name;` | | 禁用/启用约束 | `ALTER TABLE table_name DISABLE/ENABLE TRIGGER ALL;`(部分约束需特殊处理) | --- ### 约束与触发器的区别 - **约束**:声明式规则,由数据库直接强制执行,适用于简单逻辑(如唯一性、非空)。 - **触发器**:过程式逻辑(如引用[3]所述),通过编写函数实现复杂业务规则(如跨验证)[^3]。 --- #### 相关问题 1. 如何为已有添加复合唯一约束? 2. 检查约束和外键约束在数据同步场景中的优先级如何? 3. 排除约束与普通唯一约束在性能上有何差异? 4. 如何通过触发器实现约束无法覆盖的复杂业务规则?
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值