Sar*_*rov 5 database-design unique-constraint db2-midrange
所以我们目前有以下几点:
MYTABLE
COLUMN: ID (INTEGER Primary key, auto-incrementer)
COLUMN: START (DATE)
COLUMN: COMPANYID (INTEGER, Foreign key to COMPANY)
COLUMN: DELETED (INTEGER)
CHECK: DELETED = 0 OR DELETED = 1
Run Code Online (Sandbox Code Playgroud)
现在,要求允许无限删除记录,但只允许每个日期+公司的单个未删除记录。
我建议将架构更改为:
MYTABLE
COLUMN: ID (INTEGER Primary key, auto-incrementer)
COLUMN: START (DATE)
COLUMN: COMPANYID (INTEGER, Foreign key to COMPANY)
COLUMN: ACTIVE (Nullable INTEGER)
CHECK: ACTIVE = 1 OR ACTIVE IS NULL
UNIQUE: START, COMPANYID, ACTIVE
Run Code Online (Sandbox Code Playgroud)
虽然我的同事认为这“在约束上做得太过分了”,而我们应该只依赖应用程序中的唯一性检查。
这里有普遍接受的最佳实践吗?
您没有提及您所指的 DBMS,但您建议的唯一约束不适用于其中的几个,因为 null 不等于 null
create table t (x int not null, y int, unique(x,y));
insert into t (x) values (1);
insert into t (x) values (1);
Postgres12
Does not violate the constraint
Oracle18c
Violates constraint
Db2 Developer C 11.1
Does not accept nullable columns in unique constraint
Firebird 3.0
Violates constraint
MariaDB 10.4
Does not violate the constraint
MySQL 8.0
Does not violate the constraint
SQLlite 3.27
Does not violate the constraint
SQLServer 2017
Violates constraint
Run Code Online (Sandbox Code Playgroud)
所以,一般来说,你的 UNIQUE 约束不起作用。考虑将 ACTIVE 更改为
ACTIVE SMALLINT NOT NULL,
CHECK (ACTIVE BETWEEN 0 AND 1),
UNIQUE (START, COMPANYID, ACTIVE)
Run Code Online (Sandbox Code Playgroud)
虽然我不相信某个 COMPANYID 在特定的 START 可以同时是 ACTIVE 和 NOT ACTIVE,但是我不知道你的业务。
编辑:鉴于问题中的新信息,类似的事情可能是可能的(我现在无法访问系统 i 的文档,所以我不知道是否存在生成的列或表达式的约束)
create table t
( a int not null generated always as identity
, x int not null
, y int
, z int not null generated always as (
case when y is null then -1*a else y end
)
, unique(x,z)
, check (y is null or y = 1)
);
insert into t(x) values (1); -- ok
insert into t(x) values (1); -- ok
insert into t(x,y) values (1,1); -- ok
insert into t(x,y) values (1,1); -- fails because of constraint violation.
Run Code Online (Sandbox Code Playgroud)