模拟可空列的主键
Simulate a primary key for a nullable column
我在 table 中使用这种结构处理成员的角色:
- id: 行的id
- id_member:整数,外键是'members'中的'id'列 table
- id_role:整数,外键是'roles'中的'id'列 table
- date_start: 该用户获得角色的时间戳
- date_end: 该用户失去角色时的时间戳
添加角色时,date_start
设置为current_timestamp
,date_end
为空。
当我删除角色时,date_end
设置为 current_timestamp
。
不希望一个用户同时拥有多个角色,所以一开始我想设置一个三重主键:id_member
、id_role
和date_end
,但我似乎无法将可为空的列作为主键。
如何更改 table 的结构以防止用户拥有 2 个活动角色?我考虑过添加一个 active
列,但它不仅会使结构过度收费,而且我将无法保存 2 个历史角色(例如,如果用户在 4 个不同时期是 ROLE3)。
提前致谢。
I don't want a user to have several roles at the same time
部分UNIQUE
索引
因此,每个成员只能有一个活动角色 (date_end IS NULL
)。
部分 UNIQUE
索引将强制执行:
CREATE UNIQUE INDEX tbl_member_active_role_uni ON tbl (id_member)
WHERE date_end IS NULL; -- active role
参见:
- Create unique constraint with null columns
- PostgreSQL multi-column unique constraint and NULL values
EXCLUDE
以上仍然允许添加重叠的历史条目。同样,要禁止这样做,请对整数列使用 exclusion constraint. You'll need the additional module btree_gist
。参见:
然后:
ALTER TABLE tbl ADD CONSTRAINT tbl_member_no_overlapping_role
EXCLUDE USING gist (id_member with =, tsrange(date_start, date_end) WITH &&);
NULL
date_end
的值恰好完美地工作。在范围类型中,NULL
作为上限表示“无界”。
参见:
我在 table 中使用这种结构处理成员的角色:
- id: 行的id
- id_member:整数,外键是'members'中的'id'列 table
- id_role:整数,外键是'roles'中的'id'列 table
- date_start: 该用户获得角色的时间戳
- date_end: 该用户失去角色时的时间戳
添加角色时,date_start
设置为current_timestamp
,date_end
为空。
当我删除角色时,date_end
设置为 current_timestamp
。
不希望一个用户同时拥有多个角色,所以一开始我想设置一个三重主键:id_member
、id_role
和date_end
,但我似乎无法将可为空的列作为主键。
如何更改 table 的结构以防止用户拥有 2 个活动角色?我考虑过添加一个 active
列,但它不仅会使结构过度收费,而且我将无法保存 2 个历史角色(例如,如果用户在 4 个不同时期是 ROLE3)。
提前致谢。
I don't want a user to have several roles at the same time
部分UNIQUE
索引
因此,每个成员只能有一个活动角色 (date_end IS NULL
)。
部分 UNIQUE
索引将强制执行:
CREATE UNIQUE INDEX tbl_member_active_role_uni ON tbl (id_member)
WHERE date_end IS NULL; -- active role
参见:
- Create unique constraint with null columns
- PostgreSQL multi-column unique constraint and NULL values
EXCLUDE
以上仍然允许添加重叠的历史条目。同样,要禁止这样做,请对整数列使用 exclusion constraint. You'll need the additional module btree_gist
。参见:
然后:
ALTER TABLE tbl ADD CONSTRAINT tbl_member_no_overlapping_role
EXCLUDE USING gist (id_member with =, tsrange(date_start, date_end) WITH &&);
NULL
date_end
的值恰好完美地工作。在范围类型中,NULL
作为上限表示“无界”。
参见: