Return 之前和之后的 X 个元素按不唯一的 属性 排序 SQL
Return X elements before and after sorted by a property that is not unique SQL
我正在尝试编写一个查询,其中 return 个给定实体前后的 X 个元素按非唯一的 属性 排序。
例如:
属性 a
是主列(唯一的 UUID),b
是 属性 我想按
排序
table
--------
a b
--------
ag 1
sb 1
sf 1
xk 2
- bd 2
ve 2
ku 2
lt 3
ac 3
如果我想return将a=bd
前后的元素按b
排序
之前
SELECT * FROM table WHERE b >= 2 ORDER BY b DESC, a DESC LIMIT x
之后
SELECT * FROM table WHERE b <= 2 ORDER BY b ASC, a DESC OFFSET 1 LIMIT x
如果 b 的 属性 是唯一的,这将有效。我将如何在非唯一 属性.
上执行此操作
您可以使用 window 函数:
select t.*
from (select t.*,
count(*) filter (where a = 'bd') over (order by b, a rows between x preceding and x following) as cnt
from t
) t
where cnt > 0;
Here 是一个 db<>fiddle.
您可以row_number()
如下:
select a, b
from (
select t.*, max(rn) filter(where a = 'bd') over() target_rn
from (
select t.*, row_number() over(order by b, a) rn
from mytable t
) t
) t
where abs(rn - target_rn) <= 2
如果向前和向后的行数不是固定数字,您可能会发现类似的东西很有用。
with
data as (select * from t /* or filter results here if complicated */),
bck as (
select *, dense_rank() over (order by b desc) grp
from data where b < (select b from t where a = 'bd')
-- where /* try filtering here first */
order by b desc
limit 100
),
fwd as (
select *, dense_rank() over (order by b) grp
from data where b >= (select b from t where a = 'bd')
-- where /* try filtering here first */
order by b
limit 100
)
select * from bck where grp = 1
union all
select * from fwd where grp <= 2
order by b;
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=a5318a7872bf5e7dc347a00ea4b9f3fc
这是一个窗口化的实现
WITH
data AS (SELECT * FROM id_value),
before AS (
SELECT * FROM id_value
WHERE VALUE < (SELECT VALUE FROM id_value WHERE id = ID)
ORDER BY VALUE DESC, id DESC
limit 1200
),
after AS (
SELECT * FROM id_value
WHERE VALUE >= (SELECT VALUE FROM id_value WHERE id = ID)
ORDER BY VALUE ASC, id ASC
limit 1200
),
windowed AS (
(SELECT * FROM before)
UNION ALL
(SELECT * FROM after)
)
SELECT t.*
FROM (
SELECT *,
COUNT(*) filter (
WHERE id = ID
) over (
ORDER BY VALUE, id rows BETWEEN 5 preceding AND 5 following
) AS cnt
FROM windowed
) t
WHERE cnt > 0;
我正在尝试编写一个查询,其中 return 个给定实体前后的 X 个元素按非唯一的 属性 排序。
例如:
属性 a
是主列(唯一的 UUID),b
是 属性 我想按
table
--------
a b
--------
ag 1
sb 1
sf 1
xk 2
- bd 2
ve 2
ku 2
lt 3
ac 3
如果我想return将a=bd
前后的元素按b
之前
SELECT * FROM table WHERE b >= 2 ORDER BY b DESC, a DESC LIMIT x
之后
SELECT * FROM table WHERE b <= 2 ORDER BY b ASC, a DESC OFFSET 1 LIMIT x
如果 b 的 属性 是唯一的,这将有效。我将如何在非唯一 属性.
上执行此操作您可以使用 window 函数:
select t.*
from (select t.*,
count(*) filter (where a = 'bd') over (order by b, a rows between x preceding and x following) as cnt
from t
) t
where cnt > 0;
Here 是一个 db<>fiddle.
您可以row_number()
如下:
select a, b
from (
select t.*, max(rn) filter(where a = 'bd') over() target_rn
from (
select t.*, row_number() over(order by b, a) rn
from mytable t
) t
) t
where abs(rn - target_rn) <= 2
如果向前和向后的行数不是固定数字,您可能会发现类似的东西很有用。
with
data as (select * from t /* or filter results here if complicated */),
bck as (
select *, dense_rank() over (order by b desc) grp
from data where b < (select b from t where a = 'bd')
-- where /* try filtering here first */
order by b desc
limit 100
),
fwd as (
select *, dense_rank() over (order by b) grp
from data where b >= (select b from t where a = 'bd')
-- where /* try filtering here first */
order by b
limit 100
)
select * from bck where grp = 1
union all
select * from fwd where grp <= 2
order by b;
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=a5318a7872bf5e7dc347a00ea4b9f3fc
这是一个窗口化的实现
WITH
data AS (SELECT * FROM id_value),
before AS (
SELECT * FROM id_value
WHERE VALUE < (SELECT VALUE FROM id_value WHERE id = ID)
ORDER BY VALUE DESC, id DESC
limit 1200
),
after AS (
SELECT * FROM id_value
WHERE VALUE >= (SELECT VALUE FROM id_value WHERE id = ID)
ORDER BY VALUE ASC, id ASC
limit 1200
),
windowed AS (
(SELECT * FROM before)
UNION ALL
(SELECT * FROM after)
)
SELECT t.*
FROM (
SELECT *,
COUNT(*) filter (
WHERE id = ID
) over (
ORDER BY VALUE, id rows BETWEEN 5 preceding AND 5 following
) AS cnt
FROM windowed
) t
WHERE cnt > 0;