如何根据对象的 属性 对 json 或 jsonb 值内的数组中的对象进行排序?
How to sort objects in an array inside a json or jsonb value by a property of the objects?
我有这个 pl/pgsql 函数来聚合 jsonb
值(data_table_1
和 data_table_2
)中两个 table 的行。 fk_id
是 table 中的公共外键 ID:
DECLARE
v_my_variable_1 jsonb;
v_my_variable_2 jsonb;
v_combined jsonb;
BEGIN
SELECT json_agg( data_table_1 ) INTO v_my_variable FROM data_table_1 WHERE fk_id = v_id;
SELECT json_agg( data_table_2 ) into v_my_variable_2 FROM data_table_2 WHERE fk_id = v_id;
SELECT v_my_variable || v_my_variable_2 into v_combined;
现在我想按字段 ts
对 v_combined
进行排序,字段 ts
是两个 table 共有的时间戳列,因此 [=] 中所有数组对象的公共键15=]值。
示例:
v_combined = '[{"id": 1, "type": 4, "param": 3, "ts": 12354355}
, {"id": 1, "txt": "something", "args": 5, "ts": 12354345}]';
如何按 ts
的升序对 v_combined
中的数组元素进行排序?
如果我从 table 中选择,我可以简单地使用:
select * into v_combined from v_combined ORDER BY v_combined->>'ts' ASC;
但是当我尝试这样做时,它说 v_combined
不存在。有没有办法将它存储在临时 table 中并在那里排序,或者是否有直接的方法对 pl/pgsql 中的 json 对象数组进行排序?
对象中键的顺序在jsonb
文字中是无关紧要的——对象键无论如何都是在内部排序的。 (json
在这方面有所不同。)参见:
数组元素的顺序在jsonb
(或json
)文字中很重要,尽管.你的要求很有意义。您可以这样重新排序:
SELECT jsonb_agg(elem)
FROM (
SELECT *
FROM jsonb_array_elements(v_combined) a(elem)
ORDER BY (elem->>'ts')::int -- order by integer value of "ts"
) sub;
dbfiddle here
但在分配数组之前排序数组效率更高:
...
DECLARE
v_combined jsonb;
BEGIN
SELECT INTO v_combined jsonb_agg(elem)
FROM (
SELECT ts, json_agg(data_table_1) AS j
FROM data_table_1
WHERE fk_id = v_id
UNION ALL
SELECT ts, json_agg(data_table_2)
FROM data_table_2
WHERE fk_id = v_id
ORDER BY ts
) sub;
...
根据子查询中行的顺序
在标准 SQL 中,子查询(或任何 table 表达式)中行的 顺序 是也微不足道。但是在 Postgres 中,子查询中的行顺序被转移到下一个级别。所以这适用于简单的查询。甚至 documented:
... supplying the input values from a sorted subquery will usually work. For example:
SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
Beware that this approach can fail if the outer query level contains additional processing, such as a join, because that might cause the subquery's output to be reordered before the aggregate is computed.
如果您不能或不愿依赖它,则有一个安全的替代方法:向聚合函数本身添加一个 ORDER BY
。甚至更短:
SELECT INTO v_combined jsonb_agg(elem ORDER BY (elem->>'ts')::int)
FROM jsonb_array_elements(v_combined) a(elem);
但通常较慢。
我有这个 pl/pgsql 函数来聚合 jsonb
值(data_table_1
和 data_table_2
)中两个 table 的行。 fk_id
是 table 中的公共外键 ID:
DECLARE
v_my_variable_1 jsonb;
v_my_variable_2 jsonb;
v_combined jsonb;
BEGIN
SELECT json_agg( data_table_1 ) INTO v_my_variable FROM data_table_1 WHERE fk_id = v_id;
SELECT json_agg( data_table_2 ) into v_my_variable_2 FROM data_table_2 WHERE fk_id = v_id;
SELECT v_my_variable || v_my_variable_2 into v_combined;
现在我想按字段 ts
对 v_combined
进行排序,字段 ts
是两个 table 共有的时间戳列,因此 [=] 中所有数组对象的公共键15=]值。
示例:
v_combined = '[{"id": 1, "type": 4, "param": 3, "ts": 12354355}
, {"id": 1, "txt": "something", "args": 5, "ts": 12354345}]';
如何按 ts
的升序对 v_combined
中的数组元素进行排序?
如果我从 table 中选择,我可以简单地使用:
select * into v_combined from v_combined ORDER BY v_combined->>'ts' ASC;
但是当我尝试这样做时,它说 v_combined
不存在。有没有办法将它存储在临时 table 中并在那里排序,或者是否有直接的方法对 pl/pgsql 中的 json 对象数组进行排序?
对象中键的顺序在jsonb
文字中是无关紧要的——对象键无论如何都是在内部排序的。 (json
在这方面有所不同。)参见:
数组元素的顺序在jsonb
(或json
)文字中很重要,尽管.你的要求很有意义。您可以这样重新排序:
SELECT jsonb_agg(elem)
FROM (
SELECT *
FROM jsonb_array_elements(v_combined) a(elem)
ORDER BY (elem->>'ts')::int -- order by integer value of "ts"
) sub;
dbfiddle here
但在分配数组之前排序数组效率更高:
...
DECLARE
v_combined jsonb;
BEGIN
SELECT INTO v_combined jsonb_agg(elem)
FROM (
SELECT ts, json_agg(data_table_1) AS j
FROM data_table_1
WHERE fk_id = v_id
UNION ALL
SELECT ts, json_agg(data_table_2)
FROM data_table_2
WHERE fk_id = v_id
ORDER BY ts
) sub;
...
根据子查询中行的顺序
在标准 SQL 中,子查询(或任何 table 表达式)中行的 顺序 是也微不足道。但是在 Postgres 中,子查询中的行顺序被转移到下一个级别。所以这适用于简单的查询。甚至 documented:
... supplying the input values from a sorted subquery will usually work. For example:
SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
Beware that this approach can fail if the outer query level contains additional processing, such as a join, because that might cause the subquery's output to be reordered before the aggregate is computed.
如果您不能或不愿依赖它,则有一个安全的替代方法:向聚合函数本身添加一个 ORDER BY
。甚至更短:
SELECT INTO v_combined jsonb_agg(elem ORDER BY (elem->>'ts')::int)
FROM jsonb_array_elements(v_combined) a(elem);
但通常较慢。