json - 如何通过对象的属性对 json 或 jsonb 值中的数组中的对象进行排序?

标签 json postgresql sql-order-by plpgsql jsonb

我有这个 pl/pgsql 函数来聚合 jsonb 值(data_table_1data_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;

现在我想按字段 tsv_combined 进行排序,这是两个表共有的时间戳列,因此是 中所有数组对象的公共(public)键jsonb 值。

例子:

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

如何为 tsv_combined 中的数组元素进行升序排序?

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

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

但是当我尝试这样做时,它说 v_combined 不存在。有没有一种方法可以将它存储在临时表中并在那里进行排序,或者是否有一种直接的方法可以在 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 中,子查询(或任何表表达式)中的行顺序也无关紧要。但是在 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);

但它通常较慢

关于json - 如何通过对象的属性对 json 或 jsonb 值中的数组中的对象进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49206719/

相关文章:

python - 将 geojson url 转换为 pandas(解析)

java - 解析 json 时 GSON 中的数字格式异常

javascript - 从自动完成插件的 JSON 数组中获取额外参数

postgresql - Postgres 的列名或表名什么时候需要引号,什么时候不需要?

postgresql - 从 Postgres 函数返回结果集

mysql - 如何按自定义顺序对 mysql 行进行排序?

javascript - 如何将本地数组转换为远程 json 数据?

sql - PostgreSQL - 如何在函数中动态执行查询并返回表

sql - 按 Unix 时间戳 DESC 或 ASC 排序?

MYSQL 从每个类别中选择一个随机记录