我有一个包含这些表的 PostgreSQL 11 数据库:
CREATE TABLE stats (
id integer NOT NULL,
uid integer NOT NULL,
date date NOT NULL,
data jsonb DEFAULT '[]'::json NOT NULL
);
INSERT INTO stats(id, uid, date, data) VALUES
(1, 1, '2020-10-01', '{"somerandomhash":{"source":"thesource"}}');
CREATE TABLE links(
id integer NOT NULL,
uuid uuid NOT NULL,
path text NOT NULL
);
INSERT INTO links(id, uuid, path) VALUES
(1, 'acbd18db-4cc2-f85c-edef-654fccc4a4d8', 'thesource');
我的目标是使用
reports
表中的 data
创建一个新表 stats
,但使用 links
表中的新密钥。它看起来像这样:
CREATE TABLE reports(
id integer NOT NULL,
uid integer NOT NULL,
date date NOT NULL,
data jsonb DEFAULT '[]'::json NOT NULL
);
INSERT INTO reports(id, uid, date, data) VALUES
(1, 1, 2020-10-01, {"uuid":{"source":"thesource"});
为此,我尝试左连接表
links
以检索uuid
列值 - 但没有运气:
SELECT s.uid, s.date, s.data->jsonb_object_keys(data)->>'source' as path, s.data->jsonb_object_keys(data) as data, l.uuid
FROM stats s LEFT JOIN links l ON s.data->jsonb_object_keys(data)->>'source' = l.path
我尝试在左连接中使用 s.data->jsonb_object_keys(data)->>'source' 的结果,但收到错误:
ERROR: set-returning functions are not allowed in JOIN conditions
我尝试使用
LATERAL
但仍然没有有效的结果。jsonb_object_keys()
是一个设置返回函数,不能按照您的方式使用 - 正如错误消息告诉您的那样。更重要的是, json_object_keys()
返回顶级 key(s),但似乎您只对 value 感兴趣。尝试改为 jsonb_each()
:
SELECT s.id
, s.uid
, s.date
, jsonb_build_object(l.uuid::text, o.value) AS new_data
FROM stats s
CROSS JOIN LATERAL jsonb_each(s.data) o -- defaults to column names (key, value)
LEFT JOIN links l ON l.path = o.value->>'source';
jsonb_each()
返回顶级键 和 值。仅使用值继续。
嵌套的 JSON 对象似乎具有常量键名称 'source'。所以连接条件是
l.path = o.value->>'source'
。
最后,使用
jsonb
构建新的
jsonb_build_object()
值。
虽然这可以如所演示的那样工作,但仍然存在一些问题:
上面假设 stats.data
中始终存在
one顶级密钥。如果没有,您必须定义要做什么...
上面假设表
links
中始终只有一个匹配项。如果没有,您必须定义要做什么...
最重要的是,如果
data
与您想象的一样有规律,请考虑一个普通的 uuid
列(或者无论如何将其删除,因为值在表 links
中)和一个普通列 source
替换 jsonb
列。 更简单、更高效。
而不是
s.data->jsonb_object_keys(data)->>'source'
试试这个
s.data ->> 'source'
如果我的假设正确,整个查询可以这样进行:
SELECT
s.uid,
s.date,
s.data ->> 'source' AS path,
s.data -> jsonb_object_keys(data) AS data,
l.uuid
FROM stats s
LEFT JOIN links l ON s.data ->> 'source' = l.path