【问题标题】:在 Postgresql 的 JSONB 对象数组中查找具有最高值的对象
【发布时间】:2021-12-06 19:22:45
【问题描述】:

假设我们有一个表,其中 data 列存储了一个对象数组。

┌────┬───────────────────────────────────────────────────────────────────────┐
│ id │                               data                                    │
├────┼───────────────────────────────────────────────────────────────────────┤
│  1 │ [{"m2": 40.0, "sector": "Office"}, {"m2": 65.0, "room": "Hospital"}]  │
│  2 │ [{"m2": 25.0, "sector": "Cafe"}, {"m2": 120.0, "room": "Office"}]     │
│  3 │ []                                                                    │
└────┴───────────────────────────────────────────────────────────────────────┘

我只想找到m2 值最高的这些对象。

┌────┬─────────────────────────────────────────┐
│ id │                 data                    │
├────┼─────────────────────────────────────────┤
│  1 │ {"m2": 65.0, "room": "Hospital"}        │
│  2 │ {"m2": 120.0, "room": "Office"}         │
│  3 │ null                                    │
└────┴─────────────────────────────────────────┘

PostgreSQL 13.4

【问题讨论】:

    标签: sql postgresql greatest-n-per-group jsonb


    【解决方案1】:

    您可以尝试以下使用json_array_elements 扩展数组,然后使用row_number 确定具有最高m2 值的对象。

    select 
        "id", 
        (
           SELECT 
               jr 
           FROM (
               SELECT
                   jr,
                   ROW_NUMBER() OVER (
                       ORDER BY jr->'m2' DESC
                   ) as rn
               FROM
                   jsonb_array_elements("data") as jr
           ) t1
           WHERE rn=1
        ) as "data"
    from 
        my_table
    

    或者只是通过m2 订购并将结果限制在1 例如

    select 
        "id", 
        (
           SELECT 
               jr 
           FROM 
               jsonb_array_elements("data") as jr
           ORDER BY 
               jr->'m2' DESC
           LIMIT 1
        ) as "data"
    from 
        my_table
    

    View working demo db fiddle

    让我知道这是否适合你。

    【讨论】:

    • 当我们查询数十万条数据时,上述解决方案的性能是否存在差异?
    • @davidvnog 我推荐第二个更有效。如果您想确定实际的性能差异,您可以使用EXPLAIN <insert_query_here>
    【解决方案2】:

    您可以使用子查询:

    with m_d(id, a) as (
        select t1.id, (select json_agg(v.value) from jsonb_array_elements(t1.data::jsonb) v 
        where (v.value -> 'm2')::text::float = (select max((v2.value -> 'm2')::text::float) 
               from jsonb_array_elements(t1.data::jsonb) v2)) from t t1
    )
    select id, case when json_array_length(a) = 0 then null else a ->> 0 end from m_d;
    

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 1970-01-01
      • 1970-01-01
      • 2014-05-07
      • 2013-05-06
      • 2022-01-12
      • 2015-04-13
      • 2019-12-16
      • 1970-01-01
      相关资源
      最近更新 更多