如何从 jsonb 列加入嵌套值?
How to join on a nested value from a jsonb column?
我有一个带有这些 table 的 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');
我的目标是使用 stats
table 中的 data
创建一个新的 table reports
,但使用 [=] 中的新密钥17=] table。它看起来像这样:
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"});
为此,我尝试左连接 table 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
我尝试在left join中使用s.data->jsonb_object_keys(data)->>'source'的结果,但是得到了错误:
ERROR: set-returning functions are not allowed in JOIN conditions
我尝试使用 LATERAL
但仍然无效。
如何实现?
您似乎想通过 JSON 列中的 "source" 键加入。
而不是
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
jsonb_object_keys()
is a set-returning function which cannot be used the way you do - as the error messages tells you. What's more, json_object_keys()
returns top-level key(s), but it seems you are only interested in the value. Try 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';
db<>fiddle here
jsonb_each()
returns 顶级键 和 值。仅使用 value.
继续
嵌套的 JSON 对象似乎具有常量键名称 'source'。所以连接条件是l.path = o.value->>'source'
.
最后,用 jsonb_build_object()
构建新的 jsonb
值。
虽然这可以正常工作,但仍有几个问题:
上面假设在stats.data
中总是恰好有一个顶级键。如果没有,您必须定义要做什么...
上面假设在tablelinks
中总是只有一个匹配项。如果没有,您必须定义要做什么...
最重要的是:
如果 data
和你认为的一样规则,考虑一个普通的 "uuid" 列(或者删除它,因为值在 table links
中)和一个普通的列 "source" 替换 jsonb
列。 更更简单、更高效。
我有一个带有这些 table 的 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');
我的目标是使用 stats
table 中的 data
创建一个新的 table reports
,但使用 [=] 中的新密钥17=] table。它看起来像这样:
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"});
为此,我尝试左连接 table 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
我尝试在left join中使用s.data->jsonb_object_keys(data)->>'source'的结果,但是得到了错误:
ERROR: set-returning functions are not allowed in JOIN conditions
我尝试使用 LATERAL
但仍然无效。
如何实现?
您似乎想通过 JSON 列中的 "source" 键加入。
而不是
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
jsonb_object_keys()
is a set-returning function which cannot be used the way you do - as the error messages tells you. What's more, json_object_keys()
returns top-level key(s), but it seems you are only interested in the value. Try 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';
db<>fiddle here
jsonb_each()
returns 顶级键 和 值。仅使用 value.
嵌套的 JSON 对象似乎具有常量键名称 'source'。所以连接条件是l.path = o.value->>'source'
.
最后,用 jsonb_build_object()
构建新的 jsonb
值。
虽然这可以正常工作,但仍有几个问题:
上面假设在
stats.data
中总是恰好有一个顶级键。如果没有,您必须定义要做什么...上面假设在table
links
中总是只有一个匹配项。如果没有,您必须定义要做什么...最重要的是: 如果
data
和你认为的一样规则,考虑一个普通的 "uuid" 列(或者删除它,因为值在 tablelinks
中)和一个普通的列 "source" 替换jsonb
列。 更更简单、更高效。