从 jsonb(第 12 页)获取多个 key/value 对
Get multiple key/value pairs from jsonb (pg 12)
Postgres 12
table_1:
id int,
attributes jsonb,
layer_id int -- foreign key
table_2:
id int,
labels jsonb, -- this is an array, and its elements correspond to some of the keys in table_1.attributes
layer_id int -- foreign key
在 layer_id = layer_id
上加入这些表后,我只想 select table_1.attributes 中与 table_2.labels[= 中的键匹配的 key/value 对16=]
例如,如果我们有 table_1 行,例如:
attributes: { "a": 1, "b": 3, "c": "hello" },
layer_id: 5
和 table_2 行如:
labels: '["a", "c"]',
layer_id: 5
my objective 将得到包含 { "a": 1, "c": "hello" }
的列
编辑
通过以下方法我们可以获得所需的对象w/o 为每个标签获取一行(在处理数百万行时这可能会让人望而却步)
- 获取所需标签的数组
- 从属性对象中删除这些键
- 获取剩余的钥匙
- 从原始属性对象中删除那些,留下对应于所需标签的 key/values,例如,
with table_1 (layer_id, attributes) as (
values (5, '{"a": 1, "b": 3, "c": "hello"}'::jsonb),
(7, '{"d": 0, "e": 9, "f": "bye"}'::jsonb)
), table_2 (layer_id, labels) as (
values (5, '["a", "c"]'::jsonb),
(7, '[]'::jsonb)
)
select t1.layer_id,
a.attributes result
from table_1 t1
join table_2 t2 on t2.layer_id = t1.layer_id
cross join lateral (
SELECT t1.attributes - ARRAY (
SELECT
jsonb_object_keys(attributes - ARRAY (
SELECT
jsonb_array_elements_text(labels)))) AS attributes) a
group by t1.layer_id, a.attributes
layer_id | result
----------+------------------------
5 | {"a": 1, "c": "hello"}
7 | []
(2 rows)
原始解决方案
使用 jsonb_array_elements()
扩展,然后使用 jsonb_object_agg()
聚合:
with table_1 as (
select 5 as layer_id, '{"a": 1, "b": 3, "c": "hello"}'::jsonb as attributes
), table_2 as (
select 5 as layer_id, '["a", "c"]'::jsonb as labels
)
select t2.layer_id, jsonb_object_agg(l.label, t1.attributes->l.label)
from table_2 t2
cross join lateral jsonb_array_elements_text(t2.labels) as l(label)
join table_1 t1 on t1.layer_id = t2.layer_id
group by t2.layer_id;
layer_id | jsonb_object_agg
----------+------------------------
5 | {"a": 1, "c": "hello"}
(1 row)
要处理空 labels
元素,请尝试以下方法。由于 jsonb_object_agg()
不接受 null
作为标签,所以我无法弄清楚如何在不将原始查询放入 CTE 的情况下使其工作。
with table_1 (layer_id, attributes) as (
values (5, '{"a": 1, "b": 3, "c": "hello"}'::jsonb),
(7, '{"d": 0, "e": 9, "f": "bye"}'::jsonb)
), table_2 (layer_id, labels) as (
values (5, '["a", "c"]'::jsonb),
(7, '[]'::jsonb)
), expand as (
select t1.layer_id,
jsonb_object_agg(l.label, t1.attributes->l.label) result
from table_1 t1
join table_2 t2 on t2.layer_id = t1.layer_id
cross join lateral jsonb_array_elements_text(t2.labels) as l(label)
group by t1.layer_id
)
select t1.layer_id, coalesce(x.result, '[]'::jsonb) as result
from table_1 t1
left join expand x
on x.layer_id = t1.layer_id
;
layer_id | result
----------+------------------------
5 | {"a": 1, "c": "hello"}
7 | []
(2 rows)
Postgres 12
table_1:
id int,
attributes jsonb,
layer_id int -- foreign key
table_2:
id int,
labels jsonb, -- this is an array, and its elements correspond to some of the keys in table_1.attributes
layer_id int -- foreign key
在 layer_id = layer_id
上加入这些表后,我只想 select table_1.attributes 中与 table_2.labels[= 中的键匹配的 key/value 对16=]
例如,如果我们有 table_1 行,例如:
attributes: { "a": 1, "b": 3, "c": "hello" },
layer_id: 5
和 table_2 行如:
labels: '["a", "c"]',
layer_id: 5
my objective 将得到包含 { "a": 1, "c": "hello" }
编辑
通过以下方法我们可以获得所需的对象w/o 为每个标签获取一行(在处理数百万行时这可能会让人望而却步)
- 获取所需标签的数组
- 从属性对象中删除这些键
- 获取剩余的钥匙
- 从原始属性对象中删除那些,留下对应于所需标签的 key/values,例如,
with table_1 (layer_id, attributes) as (
values (5, '{"a": 1, "b": 3, "c": "hello"}'::jsonb),
(7, '{"d": 0, "e": 9, "f": "bye"}'::jsonb)
), table_2 (layer_id, labels) as (
values (5, '["a", "c"]'::jsonb),
(7, '[]'::jsonb)
)
select t1.layer_id,
a.attributes result
from table_1 t1
join table_2 t2 on t2.layer_id = t1.layer_id
cross join lateral (
SELECT t1.attributes - ARRAY (
SELECT
jsonb_object_keys(attributes - ARRAY (
SELECT
jsonb_array_elements_text(labels)))) AS attributes) a
group by t1.layer_id, a.attributes
layer_id | result
----------+------------------------
5 | {"a": 1, "c": "hello"}
7 | []
(2 rows)
原始解决方案
使用 jsonb_array_elements()
扩展,然后使用 jsonb_object_agg()
聚合:
with table_1 as (
select 5 as layer_id, '{"a": 1, "b": 3, "c": "hello"}'::jsonb as attributes
), table_2 as (
select 5 as layer_id, '["a", "c"]'::jsonb as labels
)
select t2.layer_id, jsonb_object_agg(l.label, t1.attributes->l.label)
from table_2 t2
cross join lateral jsonb_array_elements_text(t2.labels) as l(label)
join table_1 t1 on t1.layer_id = t2.layer_id
group by t2.layer_id;
layer_id | jsonb_object_agg
----------+------------------------
5 | {"a": 1, "c": "hello"}
(1 row)
要处理空 labels
元素,请尝试以下方法。由于 jsonb_object_agg()
不接受 null
作为标签,所以我无法弄清楚如何在不将原始查询放入 CTE 的情况下使其工作。
with table_1 (layer_id, attributes) as (
values (5, '{"a": 1, "b": 3, "c": "hello"}'::jsonb),
(7, '{"d": 0, "e": 9, "f": "bye"}'::jsonb)
), table_2 (layer_id, labels) as (
values (5, '["a", "c"]'::jsonb),
(7, '[]'::jsonb)
), expand as (
select t1.layer_id,
jsonb_object_agg(l.label, t1.attributes->l.label) result
from table_1 t1
join table_2 t2 on t2.layer_id = t1.layer_id
cross join lateral jsonb_array_elements_text(t2.labels) as l(label)
group by t1.layer_id
)
select t1.layer_id, coalesce(x.result, '[]'::jsonb) as result
from table_1 t1
left join expand x
on x.layer_id = t1.layer_id
;
layer_id | result
----------+------------------------
5 | {"a": 1, "c": "hello"}
7 | []
(2 rows)