您好,我们有一个名为billing_infos的表,其中在account_idstate_iddeleted_at这三个字段上创建了部分索引,其中deleted_atNULL, 我希望插入操作在try 插入account_idstate_iddeleted_at = null的重复值时失败. 但它似乎正在创建另一个具有重复项的条目.当我们判断NULL条件时,部分索引有什么需要注意的吗?我已经判断了官方的documentation,但找不到一个,下面是我的表模式的片段

Porterbizz=>\d+应用程序.billing_infos; 表格

"application.billing_infos"
     Column      |            Type             | Collation | Nullable |                        Default                        | Storage  | Stats target | Description
-----------------+-----------------------------+-----------+----------+-------------------------------------------------------+----------+--------------+-------------
 id              | integer                     |           | not null | nextval('application.billing_infos_id_seq'::regclass) | plain    |              |
 account_id      | integer                     |           | not null |                                                       | plain    |              |
 gst_in          | character varying(256)      |           | not null |                                                       | extended |              |
 gst_reg_address | character varying(256)      |           | not null |                                                       | extended |              |
 invoice_address | character varying(256)      |           | not null |                                                       | extended |              |
 state_id        | integer                     |           | not null |                                                       | plain    |              |
 default         | boolean                     |           | not null | false                                                 | plain    |              |
 deleted_at      | timestamp without time zone |           |          |                                                       | plain    |              |
Indexes:
    "billing_infos_pkey" PRIMARY KEY, btree (id)
    "account_id_state_id_deleted_at_uniq_index" UNIQUE, btree (account_id, state_id, deleted_at) WHERE deleted_at IS NULL

推荐答案

请从您的部分唯一索引中删除deleted_at,因为null永远不等于任何东西--甚至不等于另一个null.

如果没有deleted_at,则会强制实现唯一性:

# create table billing_infos (
   id int not null generated always as identity primary key,
   account_id int not null,
   state_id int not null,
   deleted_at timestamp
);
CREATE TABLE
 
# create unique index idx_1 on billing_infos (account_id, state_id) 
   where deleted_at is null;
CREATE INDEX
 
# insert into billing_infos(account_id, state_id, deleted_at) values (1, 1, null);
INSERT 0 1

# insert into billing_infos(account_id, state_id, deleted_at) values (1, 1, null);

ERROR:  duplicate key value violates unique constraint "idx_1"
DETAIL:  Key (account_id, state_id)=(1, 1) already exists.

但在索引中包括deleted_at,则复制插入成功:

# drop index idx_1;
DROP INDEX
# 
# create unique index idx_1 on billing_infos (account_id, state_id, deleted_at)
   where deleted_at is null;
CREATE INDEX
 
# insert into billing_infos(account_id, state_id, deleted_at) values (1, 1, null);
INSERT 0 1
 
# select * from billing_infos;
┌────┬────────────┬──────────┬────────────┐
│ id │ account_id │ state_id │ deleted_at │
├────┼────────────┼──────────┼────────────┤
│  1 │          1 │        1 │            │
│  3 │          1 │        1 │            │
└────┴────────────┴──────────┴────────────┘
(2 rows)

Working fiddle

Postgresql相关问答推荐

Redis作为postgreSQL嵌套数据的缓存

将real[]数组作为完整的浮点值从postquist返回

函数返回查询执行plpgsql时不存在列

创建发布性能

我需要一个变量来引用上周的星期五

如何诊断字符编码问题

自左联接的POSTGIS更新

PostgreSQL:动态SELECT查询

查找行中的最小值

postgres 和 python

如何让 Rails 使用 SSL 连接到 PostgreSQL?

如何使用 postgresql 中的存储过程将数据插入表中

使用 current_setting() 判断值

NOT LIKE 带有 NULL 值的行为

设置 Phoenix 框架和 Ecto 以使用 UUID:如何插入生成的值?

在 postgres 中创建超级用户

Postgresql:备份所有表 struct ,但只备份少数数据表

使用 PostgreSQL 的 Linq To Sql

psql 将默认 statement_timeout 设置为 postgres 中的用户

postgresql DB中唯一键的正确数据类型是什么?