【问题标题】:Ordering within a json_agg of json objects在 json 对象的 json_agg 中排序
【发布时间】:2021-01-14 11:49:39
【问题描述】:

我有一个简单的查询如下:

select json_agg(json_build_object(
                'name','name',
                'score',random(),
                'snippet','random text'
                )) as data
from table;

出于这个问题的目的,我已经简化了上述内容。

这会导致返回如下内容:

[{"name" : "name", "score" : 0.896277624648064, "snippet" : "random text"},
{"name" : "name", "score" : 0.845714892726392, "snippet" : "random text"},
{"name" : "name", "score" : 0.688958259299397, "snippet" : "random text"},
{"name" : "name", "score" : 0.870620720088482, "snippet" : "random text"},
{"name" : "name", "score" : 0.282366622239351, "snippet" : "random text"}]

有没有办法可以按对象内的分数对底层 json_agg 进行排序?

我试过了:

select json_agg(json_build_object(
                'name','name',
                'score',random(),
                'snippet','random text'
                ) order by score) as data
from table;

还有这个:

select json_agg(json_build_object(
                'name','name',
                'score',random(),
                'snippet','random text'
                ) a order by a->>'score') as data
from table;

但是以上都失败了

【问题讨论】:

    标签: sql json postgresql


    【解决方案1】:

    我看不出random() 是如何适应的。但是您可以在from 子句中生成记录,然后访问该字段:

    select json_agg(jobj order by jobj->>'score')
    from table t cross join lateral
         (values (json_build_object('name', 'name',
                                    'score', random(),
                                    'snippet', 'random text'
                                   )
                 )
         ) v(jobj);
    

    问题在于 Postgres 过度优化了上述内容并为所有行返回相同的 score。一种解决方案是关联子查询,强制评估t 中的每一行。这是一种有效的方法:

    select json_agg(jobj order by jobj->>'score')
    from t cross join lateral
         (values (json_build_object('name', 'name',
                                    'score', (case when t.n is null then random() else random() end),
                                    'snippet', 'random text'
                                   )
                 )
         ) v(jobj);
    

    Here 是一个 dbfiddle。

    【讨论】:

    • 完美,我实际上是从另一列获得分数,但获取它的查询非常复杂,因此出于问题的目的随机使用!谢谢
    【解决方案2】:

    问题在于数据不是来自预先存在的列。您需要准备好您的输入,以便在之后对其进行排序。

    例如:

    WITH input_data (name, score, snippet) AS
    (
      SELECT 'name', random(), 'random text'
      FROM generate_series(1,5) 
    )
    SELECT json_agg(input_data ORDER BY input_data.score)
    FROM input_data;
    

    【讨论】:

      猜你喜欢
      • 2022-01-14
      • 2011-09-03
      • 2011-05-12
      • 2013-07-15
      • 2020-03-06
      • 1970-01-01
      • 2018-07-08
      • 2013-10-16
      相关资源
      最近更新 更多