如何在PostgreSQL中根据字段排序获取从第二高到最低的值记录
How to get the second highest to lowest value record on the based on order by field in PostgreSQL
这里我有一个 JSON 字段,我想 select 每个 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
任何答案将不胜感激
有很多方法可以做到这一点,但如果您想玩 window 函数,您可以 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
使用 window 函数和分区,我们可以像这样抓取并消除第一行:
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
这里我有一个 JSON 字段,我想 select 每个 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
任何答案将不胜感激
有很多方法可以做到这一点,但如果您想玩 window 函数,您可以 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
使用 window 函数和分区,我们可以像这样抓取并消除第一行:
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