【问题标题】:How to get the second highest to lowest value record on the based on order by field in PostgreSQL如何在 PostgreSQL 中基于 order by 字段获得第二高到最低值的记录
【发布时间】:2021-08-04 07:24:03
【问题描述】:

这里我有一个 JSON 字段,我想在每个 id 上选择第二高到最低的记录 数据是

JSON 看起来像这样

{
    "user": [
        {
            "user_name": "Devang",
            "user_weight": 0.7676846955248864
        },
        {
            "user_name": "Meet",
            "user_weight": 1.1021
        },
        {
            "user_name": "Devang",
            "user_weight": 0.16163873153859706
        },
        {
            "user_name": "Rajan",
            "user_weight": 0.22163873153859706
        }
    ],
    "address": [
        {
            "address_name": "India"
        }
    ]
}

我执行的查询是

WITH cte AS (
SELECT id, ('{user,'||index-1||'}')::text[] as json_path, value->'user_weight'
FROM user_table, jsonb_array_elements(json_field->'user')
WITH ordinality arr(value, index) WHERE arr.value->>'user_name' IN ('Devang', 'Meet') order by id, value->'user_weight' DESC
) select * from cte;

获得这种记录

id  json_path   ?column?
1   {user,1}    1.1021
1   {user,0}    0.7676846955248864
1   {user,2}    0.16163873153859706
2   {user,0}    0.7676846955248864
2   {user,1}    0.07447325861051013

我想要这样的第二高到最低的记录

id  json_path   ?column?
1   {user,1}    1.1021 # this is the highest one in 1 id so I do not need this
1   {user,0}    0.7676846955248864
1   {user,2}    0.16163873153859706
2   {user,0}    0.7676846955248864   # this is the highest one in 2 ids so. I do not want
2   {user,1}    0.07447325861051013

输出是

id  json_path   ?column?
1   {user,0}    0.7676846955248864
1   {user,2}    0.16163873153859706
2   {user,1}    0.07447325861051013

看这里Demo

任何答案将不胜感激

【问题讨论】:

    标签: sql postgresql common-table-expression jsonb


    【解决方案1】:

    有很多方法可以做到这一点,但如果你喜欢玩窗口函数,你可以RANK()DENSE_RANK() 按 id 的权重并消除外部查询中的第一个排名:

    WITH cte AS (
      SELECT id, ('{user,'||index-1||'}')::text[] as json_path, (value->'user_weight')::text::numeric AS weight
      FROM user_table, jsonb_array_elements(json_field->'user')
      WITH ordinality arr(value, index) 
      WHERE arr.value->>'user_name' IN ('Devang', 'Meet') 
      ORDER BY id, value->'user_weight' DESC
    ) 
    SELECT * FROM (
      SELECT cte.*, 
        RANK() OVER (PARTITION BY id ORDER BY id,weight DESC
                     RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS r
      FROM cte) j
    WHERE r > 1;
    

    演示:db<>fiddle

    【讨论】:

      【解决方案2】:

      使用窗口函数和分区,我们可以像这样抓取并消除第一行:

      WITH cte AS (
         SELECT id, ('{user,'||index-1||'}')::text[] as json_path, value->'user_weight', ROW_NUMBER() OVER(PARTITION BY id order by value->'user_weight' DESC ) as row_num
         FROM user_table, jsonb_array_elements(json_field->'user')
          WITH ordinality arr(value, index) WHERE arr.value->>'user_name' IN ('Devang', 'Meet') order by id, value->'user_weight' DESC
      ) 
      select * from cte where row_num>1;
      

      这里Demo

      【讨论】:

      • 不错。请记住,如果多条记录共享相同的 max(weight),则此查询将失败。因此,它将仅跳过一条记录并显示其他记录。欢呼和快乐的编码
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 2013-08-23
      • 2010-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-03
      相关资源
      最近更新 更多