在一列可为空的多列上强制执行唯一关系

Enforcing a unique relationship over multiple columns where one column is nullable

鉴于 table

ID  PERSON_ID  PLAN  EMPLOYER_ID  TERMINATION_DATE  
1         123   ABC          321        2020-01-01
2         123   DEF          321            (null)
3         123   ABC          321            (null)
4         123   ABC          321            (null)

我想排除第 4 个条目。 (第三条显示此人被重新雇用,因此是一段新的关系。我只显示相关字段)

我的第一次尝试是简单地在 PERSON_ID / PLAN / EMPLOYER_ID / TERMINATION_DATE 上创建一个唯一索引,认为 IBMi 的 DB2 认为在唯一索引中空值相等。我显然错了...

  1. 有没有办法强制这些列的唯一性,或者,
  2. 是否有更好的方法来处理终止日期的值? (null 在技术上不正确;我认为它更多 true/false,但业务逻辑需要一个日期)

编辑

根据 7.3 的文档:

UNIQUE

Prevents the table from containing two or more rows with the same value of the index key. When UNIQUE is used, all null values for a column are considered equal. For example, if the key is a single column that can contain null values, that column can contain only one null value. The constraint is enforced when rows of the table are updated or new rows are inserted. The constraint is also checked during the execution of the CREATE INDEX statement. If the table already contains rows with duplicate key values, the index is not created.

UNIQUE WHERE NOT NULL

Prevents the table from containing two or more rows with the same value of the index key, where all null values for a column are not considered equal. Multiple null values in a column are allowed. Otherwise, this is identical to UNIQUE.

因此,我看到的行为看起来更像是 UNIQUE WHERE NOT NULL。当我为此 table 生成 SQL 时,我看到

  ADD CONSTRAINT TERMEMPPLANSSN 
  UNIQUE( TERMINATION_DATE , EMPLOYERID , PLAN_CODE , SSN ) ; 

(注意这是显示真实的字段名称,而不是我在示例中使用的名称)


编辑 2

底线,约束 !== 索引。当我回去创建一个实际的 index 时,我得到了想要的行为。

CREATE TABLE PERSON 
(
  ID INT NOT NULL
, PERSON_ID INT NOT NULL
, PLAN CHAR(3) NOT NULL
, EMPLOYER_ID INT
, TERMINATION_DATE DATE
);

INSERT INTO PERSON (ID, PERSON_ID, PLAN, EMPLOYER_ID, TERMINATION_DATE)
VALUES 
  (1, 123, 'ABC', 321, DATE('2020-01-01'))
, (2, 123, 'DEF', 321, CAST(NULL AS DATE))
, (3, 123, 'ABC', 321, CAST(NULL AS DATE))
WITH NC;

--- 不允许:---

INSERT INTO PERSON (ID, PERSON_ID, PLAN, EMPLOYER_ID, TERMINATION_DATE) VALUES 
(4, 123, 'ABC', 321, CAST(NULL AS DATE))
or
(4, 123, 'ABC', 321, DATE('2020-01-01'))

您可以:

CREATE UNIQUE INDEX PERSON_U1 ON PERSON 
(PERSON_ID, PLAN, EMPLOYER_ID, TERMINATION_DATE);

--- 不允许:---

INSERT INTO PERSON (ID, PERSON_ID, PLAN, EMPLOYER_ID, TERMINATION_DATE) VALUES 
(4, 123, 'ABC', 321, DATE('2020-01-01'))

但允许多个:

(X, 123, 'ABC', 321, CAST(NULL AS DATE))
(Y, 123, 'ABC', 321, CAST(NULL AS DATE))
...

您可以:

CREATE UNIQUE WHERE NOT NULL INDEX PERSON_U2 ON PERSON 
(PERSON_ID, PLAN, EMPLOYER_ID, TERMINATION_DATE);