定义表中不存在时删除 jsonb 键

Posted

技术标签:

【中文标题】定义表中不存在时删除 jsonb 键【英文标题】:Delete jsonb keys when not present in a definition table 【发布时间】:2019-07-05 10:35:55 【问题描述】: https://www.db-fiddle.com/f/kYghNDHwSXVKZ6uMredofZ/0 PostgreSQL 10

我在一个表(目标)中有一个 jsonb 字段,并且在另一个表(属性)中有该 json 字段的“允许”键的定义:

CREATE TABLE attributes (name TEXT);
CREATE TABLE target (custom JSONB);

INSERT INTO attributes VALUES ('a'), ('b'), ('c');
INSERT INTO target VALUES ('"a": "sth", "b": "sth"'), ('"c": "sth"'), ('"a": "sth", "d": "sth"');

所以在这个简化的例子中,允许的键是a,b and c

我现在必须编写一个迁移,从target 表中删除键和值,它们没有有效的定义。在这种情况下,这将是密钥 d

有了这些知识,我可以删除d

UPDATE target SET custom = custom - 'd';

但是 - 我如何通过比较两个表并删除 target.custom 中的所有键来做到这一点,而 attributes.name 中没有键定义?

【问题讨论】:

【参考方案1】:

您需要首先汇总目标表中每一行应删除的所有键。我假设您在该表中有一些主键列(在我的以下示例中为id)。

这个查询:

select id, array_agg(ky)
from target
   cross join jsonb_each_text(custom) as c(ky,v)
where c.ky not in (select name from attributes)
group by id;

为每个应删除的 id 收集数组中的所有键。这现在可以用作 UPDATE 语句的来源:

update target 
  set custom = custom - x.keys
from (
  select id, array_agg(ky) as keys
  from target
     cross join jsonb_each_text(custom) as c(ky,v)
     where c.ky not in (select name from attributes)
  group by id
) x
where target.id = x.id;

在线示例:https://www.db-fiddle.com/f/i7VCtjtJVErLwbS88iww7Q/0

【讨论】:

这行得通,谢谢!您的示例与我的示例相同(可能是复制+粘贴错误)。我用 id 创建了一个新的:db-fiddle.com/f/kYghNDHwSXVKZ6uMredofZ/1

以上是关于定义表中不存在时删除 jsonb 键的主要内容,如果未能解决你的问题,请参考以下文章

删除一个表中存在而另一个表中不存在的数据?

尝试定义 FOREIGN KEY 时出现“表中不存在键列”

SQL:如何定义表中不存在的额外列? [关闭]

单个查询中的 Postgresql 多个连接,其中连接的外键不存在于所有表中

如果键不存在则发送 null

PHP MySQL:如果API数据中不存在则删除行