spa*_*spa 8 postgresql update array json
我遇到了在 PostgreSQL 中使用 JSON 数据类型的问题。我尝试实现在数据库中存储非规范化的 Java 模型。该模型具有复杂对象列表。因此,我决定将它们建模为原生 PostgreSQL 数组中的 JSON。
这是我的表创建语句的精简片段:
CREATE TABLE test.persons
(
id UUID,
firstName TEXT,
lastName TEXT,
communicationData JSON[],
CONSTRAINT pk_person PRIMARY KEY (id)
);
Run Code Online (Sandbox Code Playgroud)
如您所见,它是一个以 JSON 格式显示通信数据对象列表的人。其中一个对象可能如下所示:
{"value" : "03334/254147", "typeId" : "ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf6"}
Run Code Online (Sandbox Code Playgroud)
我可以使用 PostgreSQL 的 array_append 轻松地将这样的 JSON 对象附加到数组中。但是,我无法从数组中删除已知值。考虑一下这个 SQL 语句:
UPDATE test.persons
SET communicationData = array_remove(
communicationData,
'{"value" : "03334/254147", "typeId" : "ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf6"}'::JSON
)
WHERE id = 'f671eb6a-d603-11e3-bf6f-07ba007d953d';
Run Code Online (Sandbox Code Playgroud)
这失败了ERROR: could not identify an equality operator for type json。您是否有提示我如何从 JSON 数组中删除已知值?也可以按数组中的位置删除,因为我知道一个也......
PostgreSQL 版本是 9.3.4。
Erw*_*ter 11
jsonb 在 Postgres 9.4 或更高版本中考虑Postgres 9.4 或更高版本中的jsonb数据类型。末尾的“b”代表“二进制”。除其他外,还有一个相等运算符 ( =) forjsonb。大多数人会想要转换。
json没有=为数据类型定义运算符json,因为没有明确定义的方法来建立整个json值的相等性。但见下文。
您可以转换为text然后使用=运算符。这很短,但只有在您的文本表示碰巧匹配时才有效。除了极端情况外,本质上是不可靠的。看:
或者您可以unnest使用数组并使用->>运算符来 ..get JSON object field as text并比较各个字段。
2 行:第一个像问题一样,第二个是简单的值。
CREATE TABLE tbl (
tbl_id int PRIMARY KEY
, jar json[]
);
INSERT INTO t VALUES
(1, '{"{\"value\" : \"03334/254146\", \"typeId\" : \"ea4e7d7e-7b87-4628-ba50-f5\"}"
,"{\"value\" : \"03334/254147\", \"typeId\" : \"ea4e7d7e-7b87-4628-ba50-f6\"}"
,"{\"value\" : \"03334/254148\", \"typeId\" : \"ea4e7d7e-7b87-4628-ba50-f7\"}"}')
, (2, '{"{\"value\" : \"a\", \"typeId\" : \"x\"}"
,"{\"value\" : \"b\", \"typeId\" : \"y\"}"
,"{\"value\" : \"c\", \"typeId\" : \"z\"}"}');
Run Code Online (Sandbox Code Playgroud)
您可以使用array_remove()withtext表示(不可靠)。
SELECT tbl_id
, jar, array_length(jar, 1) AS jar_len
, jar::text[] AS t, array_length(jar::text[], 1) AS t_len
, array_remove(jar::text[], '{"value" : "03334/254147", "typeId" : "ea4e7d7e-7b87-4628-ba50-f6"}'::text) AS t_result
, array_remove(jar::text[], '{"value" : "03334/254147", "typeId" : "ea4e7d7e-7b87-4628-ba50-f6"}'::text)::json[] AS j_result
FROM tbl;
Run Code Online (Sandbox Code Playgroud)
演示 2
取消嵌套单个元素的数组和测试字段。
SELECT tbl_id, array_agg(j) AS j_new
FROM tbl, unnest(jar) AS j -- LATERAL JOIN
WHERE j->>'value' <> '03334/254146'
AND j->>'typeId' <> 'ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf5'
GROUP BY 1;
Run Code Online (Sandbox Code Playgroud)
演示 3
具有行类型的替代测试。
SELECT tbl_id, array_agg(j) AS j_new
FROM tbl, unnest(jar) AS j -- LATERAL JOIN
WHERE (j->>'value', j->>'typeId') NOT IN (
('03334/254146', 'ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf5')
,('a', 'x')
)
GROUP BY 1;
Run Code Online (Sandbox Code Playgroud)
UPDATE 按照要求最后,这是您如何实现您的UPDATE:
UPDATE tbl t
SET jar = j.jar
FROM tbl t1
CROSS JOIN LATERAL (
SELECT ARRAY(
SELECT j
FROM unnest(t1.jar) AS j -- LATERAL JOIN
WHERE j->>'value' <> 'a'
AND j->>'typeId' <> 'x'
) AS jar
) j
WHERE t1.tbl_id = 2 -- only relevant rows
AND t1.tbl_id = t.tbl_id;
Run Code Online (Sandbox Code Playgroud)
db<>在这里摆弄
关于隐式LATERAL JOIN:
关于取消嵌套数组:
为了简化您的情况,请考虑规范化架构:json值(而不是数组列)的单独表,以:1 关系连接到主表。
| 归档时间: |
|
| 查看次数: |
18155 次 |
| 最近记录: |