在 postgres 查询中执行 "running json concatenation"
Do a "running json concatenation" in postgres query
是否可以为 json 做类似于 运行 求和的事情?
我有这个table:
day id data
────────────┼───────┼───────────────────
2016-06-20 │ 1 │ {"key0": "value0"}
2016-06-21 │ 1 │ {"key1": "value1"}
2016-06-22 │ 1 │ {"key2": "value2"}
我希望它是这样的 table:
day id data
────────────┼───────┼────────────────────────────────────────────────────
2016-06-20 │ 1 │ {"key0": "value0"}
2016-06-21 │ 1 │ {"key0": "value0", "key1": "value1"}
2016-06-22 │ 1 │ {"key0": "value0", "key1": "value1", "key2": "value2"}
我尝试使用 window 函数,因为聚合函数的默认行为与此类似,但我不知道如何为 json.
正确执行此操作
有人能帮忙吗?
只要您有办法定义每行的 "combined" 数据中应包含哪些其他行,就可以直接使用 LATERAL
.
testdb=# create table t(day date, id bigint, data jsonb);
ERROR: relation "t" already exists
testdb=# select * from t;
day | id | data
------------+----+--------------------
2016-06-20 | 1 | {"key0": "value0"}
2016-06-21 | 1 | {"key1": "value1"}
2016-06-22 | 1 | {"key2": "value2"}
(3 rows)
testdb=# SELECT t0.day,
t0.id,
j
FROM t t0, LATERAL
(SELECT jsonb_object(keys, vals) j
FROM (SELECT array_agg(kvset.key) keys,
array_agg(kvset.value) vals
FROM
(SELECT key, value FROM t t1
CROSS JOIN jsonb_each_text(t1.data) AS r
WHERE t1.day<=t0.day) AS kvset
) AS kvpairs
)_;
day | id | j
------------+----+--------------------------------------------------------
2016-06-20 | 1 | {"key0": "value0"}
2016-06-21 | 1 | {"key0": "value0", "key1": "value1"}
2016-06-22 | 1 | {"key0": "value0", "key1": "value1", "key2": "value2"}
在这种情况下,我使用 t1.day<=t0.day
来指示应扫描等于或小于给定日期的所有行,以便为该日期的行构建组合对象。
值得注意的是,我没有做任何事情来巧妙地处理冲突的键;当它在多行中遇到相同的键时,这可能不会做正确的事情。
没有连接 JSONB 个对象的内置聚合(jsonb_agg()
returns 一个数组,而不是单个 JSON 值),但这真的很容易创建一个:
create aggregate jsonb_append(jsonb)
(
sfunc = jsonb_concat(jsonb, jsonb),
stype = jsonb
);
此聚合也可以用作 window function,它执行 "running aggregate",因此您可以:
select day, id, jsonb_append(data) over (order by day)
from topo
order by day;
请注意 JSONB 不保留键的顺序。因此,聚合 jsonb 值中键的顺序可能与检索顺序不完全相同。
如果相同的键存在于多行中,"last"行的值(根据order by
)将被保留。
是否可以为 json 做类似于 运行 求和的事情?
我有这个table:
day id data
────────────┼───────┼───────────────────
2016-06-20 │ 1 │ {"key0": "value0"}
2016-06-21 │ 1 │ {"key1": "value1"}
2016-06-22 │ 1 │ {"key2": "value2"}
我希望它是这样的 table:
day id data
────────────┼───────┼────────────────────────────────────────────────────
2016-06-20 │ 1 │ {"key0": "value0"}
2016-06-21 │ 1 │ {"key0": "value0", "key1": "value1"}
2016-06-22 │ 1 │ {"key0": "value0", "key1": "value1", "key2": "value2"}
我尝试使用 window 函数,因为聚合函数的默认行为与此类似,但我不知道如何为 json.
正确执行此操作有人能帮忙吗?
只要您有办法定义每行的 "combined" 数据中应包含哪些其他行,就可以直接使用 LATERAL
.
testdb=# create table t(day date, id bigint, data jsonb);
ERROR: relation "t" already exists
testdb=# select * from t;
day | id | data
------------+----+--------------------
2016-06-20 | 1 | {"key0": "value0"}
2016-06-21 | 1 | {"key1": "value1"}
2016-06-22 | 1 | {"key2": "value2"}
(3 rows)
testdb=# SELECT t0.day,
t0.id,
j
FROM t t0, LATERAL
(SELECT jsonb_object(keys, vals) j
FROM (SELECT array_agg(kvset.key) keys,
array_agg(kvset.value) vals
FROM
(SELECT key, value FROM t t1
CROSS JOIN jsonb_each_text(t1.data) AS r
WHERE t1.day<=t0.day) AS kvset
) AS kvpairs
)_;
day | id | j
------------+----+--------------------------------------------------------
2016-06-20 | 1 | {"key0": "value0"}
2016-06-21 | 1 | {"key0": "value0", "key1": "value1"}
2016-06-22 | 1 | {"key0": "value0", "key1": "value1", "key2": "value2"}
在这种情况下,我使用 t1.day<=t0.day
来指示应扫描等于或小于给定日期的所有行,以便为该日期的行构建组合对象。
值得注意的是,我没有做任何事情来巧妙地处理冲突的键;当它在多行中遇到相同的键时,这可能不会做正确的事情。
没有连接 JSONB 个对象的内置聚合(jsonb_agg()
returns 一个数组,而不是单个 JSON 值),但这真的很容易创建一个:
create aggregate jsonb_append(jsonb)
(
sfunc = jsonb_concat(jsonb, jsonb),
stype = jsonb
);
此聚合也可以用作 window function,它执行 "running aggregate",因此您可以:
select day, id, jsonb_append(data) over (order by day)
from topo
order by day;
请注意 JSONB 不保留键的顺序。因此,聚合 jsonb 值中键的顺序可能与检索顺序不完全相同。
如果相同的键存在于多行中,"last"行的值(根据order by
)将被保留。