如何通过对象属性对 JSON 数组中的对象进行排序?

问题描述 投票:0回答:1

我有这个 PL/pgSQL 函数,可以将两个表中的行聚合为

jsonb
值(
data_table_1
data_table_2
)。
fk_id
是两个表中共同的外键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
进行排序,这是两个表共有的时间戳列,因此是
jsonb
值中所有数组对象中的公共键。

示例:

v_combined = '[{"id": 1, "type": 4, "param": 3, "ts": 12354355}
             , {"id": 1, "txt": "something", "args": 5, "ts": 12354345}]';

如何对

v_combined
中的数组元素按升序对
ts
进行排序?

如果我从表格中选择,我可以简单地使用:

select * into v_combined from v_combined ORDER BY v_combined->>'ts' ASC;

但是当我尝试这样做时,它说

v_combined
不存在。有没有办法将其存储在临时表中并在那里排序,或者有没有直接的方法在 PL/pgSQL 中对 JSON 对象数组进行排序?

json postgresql sql-order-by plpgsql jsonb
1个回答
24
投票

对象中键的顺序

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 这里

但是在

分配数组之前对数组进行排序会更高效

... 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 中,子查询(或任何表表达式)中的

行顺序也无关紧要。但在 Postgres 中,子查询中的行顺序被转移到下一个级别。所以这适用于简单的查询。它甚至被记录在案

...从排序子查询提供输入值通常会起作用。例如:

SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
请注意,如果外部查询级别包含附加处理(例如联接),此方法可能会失败,因为这可能会导致子查询的输出在计算聚合之前重新排序。

如果您不能或不会依赖于此,还有一个安全的替代方案:向聚合函数本身添加

ORDER BY

。甚至更短:

SELECT INTO v_combined jsonb_agg(elem ORDER BY (elem->>'ts')::int) FROM jsonb_array_elements(v_combined) a(elem);
但通常

较慢

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.