我们有一个遗留数据库架构,该架构具有一些有趣的设计决策。直到最近,我们仅支持Oracle和SQL
Server,但是我们试图添加对PostgreSQL的支持,这带来了一个有趣的问题。我已经搜索了Stack
Overflow和Internet的其余部分,但我不认为这种特殊情况是重复的。
对于唯一约束中的可为空的列,Oracle和SQL Server的行为相同,这实际上是在执行唯一检查时忽略为NULL的列。
假设我有下表和约束条件:
CREATE TABLE EXAMPLE
(
ID TEXT NOT NULL PRIMARY KEY,
FIELD1 TEXT NULL,
FIELD2 TEXT NULL,
FIELD3 TEXT NULL,
FIELD4 TEXT NULL,
FIELD5 TEXT NULL,
...
);
CREATE UNIQUE INDEX EXAMPLE_INDEX ON EXAMPLE
(
FIELD1 ASC,
FIELD2 ASC,
FIELD3 ASC,
FIELD4 ASC,
FIELD5 ASC
);
在Oracle和SQL Server上,保留任何可为空的列NULL
都将导致仅对非null列执行唯一性检查。因此,以下插入操作只能执行一次:
INSERT INTO EXAMPLE VALUES ('1','FIELD1_DATA', NULL, NULL, NULL, NULL );
INSERT INTO EXAMPLE VALUES ('2','FIELD1_DATA','FIELD2_DATA', NULL, NULL,'FIELD5_DATA');
-- These will succeed when they should violate the unique constraint:
INSERT INTO EXAMPLE VALUES ('3','FIELD1_DATA', NULL, NULL, NULL, NULL );
INSERT INTO EXAMPLE VALUES ('4','FIELD1_DATA','FIELD2_DATA', NULL, NULL,'FIELD5_DATA');
但是,由于PostgreSQL(正确地)遵循SQL标准,所以这些插入(以及其中任何一个值是NULL的任何其他组合)都不会引发错误,并且可以正确插入。不幸的是,由于我们的旧模式和支持代码,我们需要PostgreSQL与SQLServer和Oracle表现相同。
我知道以下堆栈溢出问题及其答案:创建具有nullcolumn的唯一约束。据我了解,有两种解决此问题的策略:
NULL
和的情况下,创建描述索引的部分索引NOT NULL
(这会导致部分索引的数量呈指数增长)COAELSCE
与索引中可为空的列上的哨兵值一起使用。(1)的问题在于,我们需要创建的部分索引的数量与我们想要添加到约束中的每个其他可空列成指数增长(如果我没有记错的话,则为2 ^
N)。(2)的问题是哨兵值减少了该列的可用值数量,并减少了所有潜在的性能问题。
我的问题:这是该问题的仅有的两种解决方案吗?如果是这样,那么在此特定用例之间它们之间的权衡是什么?一个好的答案将讨论每种解决方案的性能,可维护性,PostgreSQL如何在简单的SELECT
语句中利用这些索引以及任何其他“陷阱”或需要注意的事情。请记住,5个可为空的列仅作为示例;我们的架构中有一些表格,最多可以有10个表格(是的,每次看到它我都会哭,但这就是事实)。
您正在努力与现有的 Oracle 和 SQL Server 实现 兼容 。
这是一个比较三个涉及的RDBS的物理行存储格式的演示。
由于Oracle根本不实现NULL
行存储中的值,因此NULL
无论如何也无法分辨出空字符串与字符串之间的区别。因此,对于 这种
特殊的用例,使用空字符串(''
)代替NULL
Postgres中的值是否明智? __
将唯一约束中包含的列定义为NOT NULL DEFAULT ''
,已解决的问题:
CREATE TABLE example (
example_id serial PRIMARY KEY
, field1 text NOT NULL DEFAULT ''
, field2 text NOT NULL DEFAULT ''
, field3 text NOT NULL DEFAULT ''
, field4 text NOT NULL DEFAULT ''
, field5 text NOT NULL DEFAULT ''
, CONSTRAINT example_index UNIQUE (field1, field2, field3, field4, field5)
);
CREATE UNIQUE INDEX ...
而不是您一直在谈论的 唯一 约束 。有细微,重要的差异!
* [PostgreSQL如何执行UNIQUE约束/它使用什么类型的索引?](https://stackoverflow.com/questions/9066972/how-does-postgresql-enforce-the-unique-constraint-what-type-of-index-does-it-u/9067108#9067108)
我将其更改为实际约束,就像您将其作为帖子主题一样。
关键字ASC
只是noise,因为这是默认的排序顺序。我把它丢了。
serial
为简单起见,使用PK列是完全可选的,但通常比存储为的数字更好text
。
只需从中忽略空/空字段INSERT
:
INSERT INTO example(field1) VALUES ('F1_DATA');
INSERT INTO example(field1, field2, field5) VALUES ('F1_DATA', 'F2_DATA', 'F5_DATA');
重复任何这些插入操作都会违反唯一约束。
或者, 如果您坚持要省略目标列(这在持久化INSERT
语句中有点反模式):
或者 对于需要列出所有列的批量插入:
INSERT INTO example VALUES
('1', 'F1_DATA', DEFAULT, DEFAULT, DEFAULT, DEFAULT)
, ('2', 'F1_DATA','F2_DATA', DEFAULT, DEFAULT,'F5_DATA');
或者 简单地:
INSERT INTO example VALUES
('1', 'F1_DATA', '', '', '', '')
, ('2', 'F1_DATA','F2_DATA', '', '','F5_DATA');
或者,您可以编写一个BEFORE INSERT OR UPDATE
转换NULL
为的触发器''
。
如果您需要使用实际的NULL值,则建议使用唯一 索引 , COALESCE
就像您在选项(2)中提到的那样,并在最后一个示例中提供@wildplasser。
像@Rudolfo这样的 数组
上的索引很简单,但是要昂贵得多。数组处理在Postgres中并不是很便宜,并且存在类似于行(24字节)的数组开销
数组仅限于相同数据类型的列。您可以将所有列都强制转换为,text
如果不是,则通常会进一步增加存储需求。或者您可以将众所周知的行类型用于异构数据类型…
一个极端的情况:具有所有NULL值的数组(或行)类型被视为相等(!),因此只能有1行且所有涉及的列均为NULL。可能会或可能不会符合要求。
问题内容: 有没有一种方法可以使用JPA指定在不同的列集上应该有多个唯一约束? 我已经看到了特定于hibernate的注释,但是由于我们仍在确定hibernate和数据核之间的关系,因此我试图避免使用特定于供应商的解决方案。 问题答案: 所述的属性实际接受的这些阵列。您的示例只是具有单个元素的数组的简写。否则,它看起来像: 只要唯一性约束仅基于一个字段,就可以在该列上使用。
问题内容: 假设我们有这些表: 是否有可能在上创建唯一约束,使得对于最多一个引用中的所有行,其值都为??陈述另一种方法,我可以创建一个唯一约束,以便上述表的连接没有重复项吗?我没有考虑- 我可以找到的每个数据库的语法似乎都与每个约束都限制在一个表上- 但这可能是我缺乏想象力的原因。(当然,去规范化以包含on是一种解决方案。) 问题答案: 您可以尝试以下方法。您必须在Parent中创建一个冗余的UN
我想添加一个约束,只在表的一部分中对列强制唯一性。 上面的部分是一厢情愿的想法。 有办法吗?还是应该回到关系绘图板?
关于Oracle中对可为空的列进行唯一约束定义的可能解决方案,我想向你们请教/收集一些想法。 null 现在困难的部分来了。我决定,在这个表中,可以存储更多(独立)客户的数据。为此,我添加了名为customer_code的新列。这段代码实际上将表分割成不同的空格,而每个客户只能看到自己的数据。 为此,引入了oracle vpd(虚拟专用数据库)。 每个客户都使用自己的oracle用户 登录时,将加
我对Postgres Unique约束有问题,该约束包含多个可能包含空值的列。 让我们假设这种情况: Insert将插入('foo',bar')一次和('foo',NULL)两次(尽管直觉告诉它应该插入一次)。 在这种情况下,解决方案非常简单。我可以添加唯一的索引 但是当有更多的列和不同的类型(不仅仅是文本)时,问题就开始了。假设我们有10列,其中9列可以有值。也许我可以用大量的限制来解决它,但这
问题内容: 我正在将SEAM 2 / Hibernate与PostgreSQL 9数据库一起使用。我有下表 我想添加一个约束,以确保每个新条目都具有active_band_user和active_band_date的唯一组合。 每秒可能有许多次尝试插入,因此我需要尽可能地提高效率,是否可以在实体映射中使用SEAM /hibernate注释? 提前致谢 问题答案: 没有Hibernate注释在插入/