Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 具有空值的唯一列值组合_Sql_Postgresql - Fatal编程技术网

Sql 具有空值的唯一列值组合

Sql 具有空值的唯一列值组合,sql,postgresql,Sql,Postgresql,我试图有条件地向表中插入一些数据,其中每个列值组合在表中最多只能出现一次。架构如下所示: CREATE TABLE foobar ( id SERIAL PRIMARY KEY, a_id INTEGER, b_id INTEGER, c_id INTEGER, ident VARCHAR(32), date_a timestamp, date_b timestamp, FOREIGN KEY a_id REFERENCES a (

我试图有条件地向表中插入一些数据,其中每个列值组合在表中最多只能出现一次。架构如下所示:

CREATE TABLE foobar (
    id SERIAL PRIMARY KEY,
    a_id INTEGER,
    b_id INTEGER,
    c_id INTEGER,
    ident VARCHAR(32),
    date_a timestamp,
    date_b timestamp,
    FOREIGN KEY a_id REFERENCES a (id) ON DELETE CASCADE,
    FOREIGN KEY b_id REFERENCES b (id) ON DELETE CASCADE,
    FOREIGN KEY c_id REFERENCES c (id) ON DELETE CASCADE));
(a_id、b_id、c_id、ident)的组合是唯一的,但仅适用于日期a和日期b均为空的行

我希望仅当a_id、b_id、c_id、任务组合不在数据库中时才能插入新行。如果是,它不必做任何事情

起初,我试图在这些列上创建一个唯一的约束,但问题是a_id、b_id和c_id允许为NULL,只要它们中至少有一个不为NULL。这会破坏唯一约束。因为a、b和c_id字段是外键,所以我不能将它们设置为其他存根值(如-1)

我尝试使用锁定(与我更好的判断相反),结果在测试的几分钟内出现了死锁


这个问题有没有标准的解决方案?

与其使用唯一的约束,还不如使用一个唯一的索引来确定要检查的确切条件。然后可以将空值合并为伪值,如-1。比如:

CREATE UNIQUE INDEX
foobar_test ON foobar
(COALESCE(a_id, -1), COALESCE(b_id, -1), COALESCE(c_id, -1), ident) -- Nulls become -1
WHERE date_a is null and date_b is null; -- Only check when date_a and date_b is null

这将确保
a_id
b_id
c_id
ident
对于
date_a
date_b
均为
null

的所有行都是唯一的(包括它们的空值组合),而不是使用唯一约束,您可能应该对要检查的确切条件使用唯一索引。然后可以将空值合并为伪值,如-1。比如:

CREATE UNIQUE INDEX
foobar_test ON foobar
(COALESCE(a_id, -1), COALESCE(b_id, -1), COALESCE(c_id, -1), ident) -- Nulls become -1
WHERE date_a is null and date_b is null; -- Only check when date_a and date_b is null

这将确保
a_-id
b_-id
c_-id
ident
对于
date_-a
date_-b
都是
null

的所有行都是唯一的(包括它们的空值组合),在我的多个生产性数据库中类似的情况下,我只是添加一个“默认行”指向引用的表。我对这些表使用
id=0
,并在10或100处启动真正的代理键。或者,如果保留
0
,您可以使用
-1
(或任何适合您的选项)

通过这种方式,我可以将所有fk列设置为
notnull默认值0
和(部分)
UNIQUE
约束开箱即用:

CREATE UNIQUE INDEX tbl_uni_idx ON tbl (a_id, b_id, c_id, ident)
WHERE date_a IS NULL AND date_b IS NULL;

在类似的情况下,在我的多个生产性数据库中,我只需向引用的表添加一个“默认行”。我使用
id=0
,并在10或100处启动真正的代理键。或者,如果保留
0
,您可以使用
-1
(或任何适合您的选项)

通过这种方式,我可以将所有fk列设置为
notnull默认值0
和(部分)
UNIQUE
约束开箱即用:

CREATE UNIQUE INDEX tbl_uni_idx ON tbl (a_id, b_id, c_id, ident)
WHERE date_a IS NULL AND date_b IS NULL;

您希望将此逻辑作为一种约束/触发器(违反时抛出错误)?还是将其添加到INSERT语句中(违反时不执行任何操作)?如果a_id、b_id和c_id可以为null,为什么要将它们作为外键?事实上,postgresql甚至允许这样做吗?@DanBracuk.。您可以先进行选择,看看是否存在冲突的值吗?这是什么意思?这破坏了唯一约束?对于唯一索引,null被认为是不同的。或者您想被考虑吗d等于@Mike的答案中的(-1)?您希望将此逻辑作为一种约束/触发器(违反时抛出错误)?还是将其添加到INSERT语句中(违反时不执行任何操作)?如果a_id、b_id和c_id可以为null,为什么要将它们作为外键?事实上,postgresql甚至允许这样做吗?@DanBracuk.。您可以先进行选择,看看是否存在冲突的值吗?这是什么意思?这破坏了唯一约束?对于唯一索引,null被认为是不同的。或者您想被考虑吗d等于@Mike的答案中的(-1)?它考虑过这样做,但它增加了另一层东西可能出错的地方,我不是特别喜欢它。它考虑过这样做,但它增加了另一层东西可能出错的地方,我不是特别喜欢它。