【问题标题】:Unique constraint on JSONB null fieldJSONB 空字段的唯一约束
【发布时间】:2018-08-07 02:32:21
【问题描述】:

让我用一个简单的例子来描述我的问题。假设我有一个只有两个字段的表 t,自动“id”和一个 jsonb 类型的“信息”字段:

CREATE TABLE t(
  ID serial NOT NULL PRIMARY KEY,
  info jsonb NOT NULL
);

'info' 可能有字段 'a'、'b'、'c' 以及其他一些字段。字段 'c' 可能为空,我希望 (a, b, c) 是唯一的,因此我在它们上创建了唯一索引:

CREATE UNIQUE INDEX idx_abc ON t (
  (info ->> 'a'), (info ->> 'b'), (info ->> 'c')
);

但后来我意识到,如果 'c' 为 null,则此唯一约束根本不起作用。例如,我可以插入多行:

insert into t(info) values('{"a": "a1", "b": "b1"}')

insert into t(info) values('{"a": "a1", "b": "b1", "c": null}')

我目前的解决方案是无论如何给“c”一个值,如果“c”为空,那么我设置“空”:

insert into t(info) values('{"a": "a1", "b": "b1", "c": "null"}')

如果我运行插入两次,这种方式将触发唯一约束。但我觉得这只是一种解决方法,我想知道是否有更好的解决方案来允许唯一约束工作,即使字段“c”为空。

【问题讨论】:

  • BSON?你的意思是jsonb,对吧?请记住始终声明您的 Postgres 版本。

标签: postgresql database-design null unique-constraint jsonb


【解决方案1】:

如果它只是一个可能具有 NULL 值的键,那么部分索引将是一种有效的解决方案,如下所述:

更通用(效率较低)的解决方案是使用COALESCE

CREATE UNIQUE INDEX idx_abc ON t (
   COALESCE(info ->> 'a', 'NULL')
 , COALESCE(info ->> 'b', 'NULL')
 , COALESCE(info ->> 'c', 'NULL')
);

这样,您将实际的NULL 值和字符串“NULL”(任意示例)折叠为相同的值。就像您已经做的那样,但您不需要弄乱原始列值。

我还会考虑从jsonb 文档中提取涉及的键作为常规 Postgres 列(冗余或不冗余),以便拥有完整的关系工具库供您使用:(NOT NULL) 约束、默认值等。更快,也是。

【讨论】:

  • 这对我不起作用:COALESCE(info ->> 'a', 'NULL') 我不得不将其更改为 COALESCE(info ->> 'a', NULL) 然后它起作用了。尽管如此,还是感谢您提供的示例,它非常有帮助。
  • @JavierBuzzi:这是一种误解。 COALESCE(info ->> 'a', NULL) 中的 COALESCE 包装器是无操作的(什么都不做)。这里的重点是将NULL 值替换为非空值,因此UNIQUE 约束生效。点击上面的链接了解更多说明。
  • 也许对于 OP 的例子,对于我来说,如果它不存在,我想忽略它。
  • 不确定您的目标,但 COALESCE(info ->> 'a', NULL) 可以总是替换为 info ->> 'a'
猜你喜欢
  • 2016-08-29
  • 2019-09-29
  • 2023-02-13
  • 1970-01-01
  • 1970-01-01
  • 2018-05-28
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
相关资源
最近更新 更多