PostgreSQL - 将底部的 N 个结果切片并将它们移动到顶部

PostgreSQL - Slice the bottom N results and move them to the top

比方说,我有一个像这样检索的电子邮件地址列表:

SELECT email FROM users ORDER BY email

这个returns:

a@email.com
b@email.com
c@email.com
...
x@email.com
y@email.com
z@email.com

我想获取此结果集,将底部的 3 封电子邮件切分并移至顶部,这样您会看到如下结果集:

x@email.com
y@email.com
z@email.com -- Note x-z is here
a@email.com
b@email.com
c@email.com
...
u@email.com
v@email.com
w@email.com

有没有办法在 SQL 中做到这一点?出于内存原因,我不想在应用程序端执行此操作。

如果您知道这些值为 "x" 或更大,您可以简单地执行以下操作:

order by (case when email >= 'x@email.com' then 1 else 2 end),
         email

否则,您可以使用row_number():

select email
from (select email, row_number() over (order by email desc) as seqnum
      from users u
     ) u
order by (case when seqnum <= 3 then 1 else 2 end),
         email;

这是一个具有 window 函数 row_number()count() 的版本:

SELECT email
  FROM (
    SELECT row_number() OVER (ORDER BY email), count(*) OVER (), email
      FROM users
  ) sq1
  ORDER BY count - 3 >= row_number, email;

假设 email 定义为 UNIQUE NOT NULL。否则你需要做更多。

SELECT email
FROM  (SELECT email, row_number() OVER (ORDER BY email DESC) AS rn FROM users) sub
ORDER  BY (rn > 3), rn DESC;

在 Postgres 中,您可以按 boolean 表达式排序。 FALSETRUE 之前排序。更多:

  • Sorting null values after all others, except special

其次,按计算的行号(rn)降序排序。下次不要按(更昂贵的)文本列 email 排序。更短更简单 - 用 EXPLAIN ANALYZE 测试,它也应该更快。