postgresql 中的 Rownum

发布于 2024-09-27 14:33:05 字数 37 浏览 4 评论 0原文

有没有办法在 postgresql 中模拟 rownum ?

Is there any way to simulate rownum in postgresql ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

烟凡古楼 2024-10-04 14:33:05

PostgreSQL > 8.4

SELECT 
    row_number() OVER (ORDER BY col1) AS i, 
    e.col1, 
    e.col2, 
    ... 
FROM ... 

Postgresql > 8.4

SELECT 
    row_number() OVER (ORDER BY col1) AS i, 
    e.col1, 
    e.col2, 
    ... 
FROM ... 
So要识趣 2024-10-04 14:33:05

Postgresql 有限制。

Oracle的代码:

select *
from
  tbl
where rownum <= 1000;

与Postgresql的代码相同:

select *
from
  tbl
limit 1000

Postgresql have limit.

Oracle's code:

select *
from
  tbl
where rownum <= 1000;

same in Postgresql's code:

select *
from
  tbl
limit 1000
黄昏下泛黄的笔记 2024-10-04 14:33:05

我刚刚在 Postgres 9.1 中测试了一个接近 Oracle ROWNUM 的解决方案:

select row_number() over() as id, t.*
from information_schema.tables t;

I have just tested in Postgres 9.1 a solution which is close to Oracle ROWNUM:

select row_number() over() as id, t.*
from information_schema.tables t;

如果您只想返回一个号码,请尝试此操作。

create temp sequence temp_seq;
SELECT inline_v1.ROWNUM,inline_v1.c1
FROM
(
select nextval('temp_seq') as ROWNUM, c1 
from sometable
)inline_v1;

您可以向 inline_v1 SQL 添加 order by,以便您的 ROWNUM 对您的数据具有一定的顺序意义。

select nextval('temp_seq') as ROWNUM, c1 
from sometable
ORDER BY c1 desc;

可能不是最快的,但如果您确实需要它们,它是一个选择。

If you just want a number to come back try this.

create temp sequence temp_seq;
SELECT inline_v1.ROWNUM,inline_v1.c1
FROM
(
select nextval('temp_seq') as ROWNUM, c1 
from sometable
)inline_v1;

You can add a order by to the inline_v1 SQL so your ROWNUM has some sequential meaning to your data.

select nextval('temp_seq') as ROWNUM, c1 
from sometable
ORDER BY c1 desc;

Might not be the fastest, but it's an option if you really do need them.

黎歌 2024-10-04 14:33:05

如果您有唯一键,则可以使用 COUNT(*) OVER ( ORDER BY unique_key ) as ROWNUM

SELECT t.*, count(*) OVER (ORDER BY k ) ROWNUM 
FROM yourtable t;

| k |     n | rownum |
|---|-------|--------|
| a | TEST1 |      1 |
| b | TEST2 |      2 |
| c | TEST2 |      3 |
| d | TEST4 |      4 |

演示

If you have a unique key, you may use COUNT(*) OVER ( ORDER BY unique_key ) as ROWNUM

SELECT t.*, count(*) OVER (ORDER BY k ) ROWNUM 
FROM yourtable t;

| k |     n | rownum |
|---|-------|--------|
| a | TEST1 |      1 |
| b | TEST2 |      2 |
| c | TEST2 |      3 |
| d | TEST4 |      4 |

DEMO

年少掌心 2024-10-04 14:33:05

我认为可以使用临时序列来模拟 Oracle rownum。

create or replace function rownum_seq() returns text as $
select concat('seq_rownum_',replace(uuid_generate_v4()::text,'-','_'));
$ language sql immutable;

create or replace function rownum(r record, v_seq_name text default rownum_seq()) returns bigint as $
declare 
begin
    return nextval(v_seq_name);
exception when undefined_table then
    execute concat('create temporary sequence ',v_seq_name,' minvalue 1 increment by 1');
    return nextval(v_seq_name);
end;
$ language plpgsql volatile;

演示:

select ccy_code,rownum(a.*) from (select ccy_code from currency order by ccy_code desc) a where rownum(a.*)<10;

给出:

ZWD 1
ZMK 2
ZBH 3
ZAR 4
YUN 5
YER 6
XXX 7
XPT 8
XPF 9

说明:

函数 rownum_seq() 是不可变的,PG 在查询中仅调用一次,因此我们得到相同的唯一序列名称(即使该函数在同一个查询中被调用数千次)

函数 rownum() 是易失性的并由 PG 每次调用(即使在 where 子句中)

如果没有 r 记录参数(未使用),则函数 rownum() 可能会过早求值。这就是棘手的一点。想象一下,下面的 rownum() 函数:

create or replace function rownum(v_seq_name text default rownum_seq()) returns bigint as $
declare 
begin
    return nextval(v_seq_name);
exception when undefined_table then
    execute concat('create temporary sequence ',v_seq_name,' minvalue 1 increment by 1');
    return nextval(v_seq_name);
end;
$ language plpgsql volatile;


explain select ccy_code,rownum() from (select ccy_code from currency order by ccy_code desc) a where rownum()<10

Sort  (cost=56.41..56.57 rows=65 width=4)
  Sort Key: currency.ccy_code DESC
  ->  Seq Scan on currency  (cost=0.00..54.45 rows=65 width=4)
        Filter: (rownum('649aec1a-d512-4af0-87d8-23e8d8a9d982'::text) < 10)

PG 在订单之前应用过滤器。该死!
使用第一个未使用的参数,我们强制 PG 在过滤器之前排序:

explain select * from (select ccy_code from currency order by ccy_code desc) a where rownum(a.*)<10;

Subquery Scan on a  (cost=12.42..64.36 rows=65 width=4)
  Filter: (rownum(a.*, 'seq_rownum_43b5c67f_dd64_4191_b29c_372061c848d6'::text) < 10)
  ->  Sort  (cost=12.42..12.91 rows=196 width=4)
        Sort Key: currency.ccy_code DESC
        ->  Seq Scan on currency  (cost=0.00..4.96 rows=196 width=4)

优点:

  • 作为表达式或在 where 子句中使用
  • 易于使用:只需传递 from 中的第一条记录。* 缺点

  • 为每个创建一个临时序列rownum() 遇到,但在会话结束时被删除。
  • 性能(讨论,row_number() 优于 () 与 nextval)

I think it's possible to mimic Oracle rownum using temporary sequences.

create or replace function rownum_seq() returns text as $
select concat('seq_rownum_',replace(uuid_generate_v4()::text,'-','_'));
$ language sql immutable;

create or replace function rownum(r record, v_seq_name text default rownum_seq()) returns bigint as $
declare 
begin
    return nextval(v_seq_name);
exception when undefined_table then
    execute concat('create temporary sequence ',v_seq_name,' minvalue 1 increment by 1');
    return nextval(v_seq_name);
end;
$ language plpgsql volatile;

Demo:

select ccy_code,rownum(a.*) from (select ccy_code from currency order by ccy_code desc) a where rownum(a.*)<10;

Gives:

ZWD 1
ZMK 2
ZBH 3
ZAR 4
YUN 5
YER 6
XXX 7
XPT 8
XPF 9

Explanations:

Function rownum_seq() is immutable, called only once by PG in a query, so we get the same unique sequence name (even if the function is called thousand times in the same query)

Function rownum() is volatile and called each time by PG (even in a where clause)

Without r record parameter (which is unused), the function rownum() could be evaluated too early. That's the tricky point. Imagine, the following rownum() function:

create or replace function rownum(v_seq_name text default rownum_seq()) returns bigint as $
declare 
begin
    return nextval(v_seq_name);
exception when undefined_table then
    execute concat('create temporary sequence ',v_seq_name,' minvalue 1 increment by 1');
    return nextval(v_seq_name);
end;
$ language plpgsql volatile;


explain select ccy_code,rownum() from (select ccy_code from currency order by ccy_code desc) a where rownum()<10

Sort  (cost=56.41..56.57 rows=65 width=4)
  Sort Key: currency.ccy_code DESC
  ->  Seq Scan on currency  (cost=0.00..54.45 rows=65 width=4)
        Filter: (rownum('649aec1a-d512-4af0-87d8-23e8d8a9d982'::text) < 10)

PG apply the filter before the order. Damned!
With the first unused parameter, we force PG to order before filter:

explain select * from (select ccy_code from currency order by ccy_code desc) a where rownum(a.*)<10;

Subquery Scan on a  (cost=12.42..64.36 rows=65 width=4)
  Filter: (rownum(a.*, 'seq_rownum_43b5c67f_dd64_4191_b29c_372061c848d6'::text) < 10)
  ->  Sort  (cost=12.42..12.91 rows=196 width=4)
        Sort Key: currency.ccy_code DESC
        ->  Seq Scan on currency  (cost=0.00..4.96 rows=196 width=4)

Pros:

  • works as an expression or in a where clause
  • easy to use: just pass the first record.* you have in the from

Cons:

  • a temporary sequence is created for each rownum() encountered, but it is removed when session ends.
  • performance (to discuss, row_number() over () versus nextval)
铁憨憨 2024-10-04 14:33:05

Postgresql 没有相当于 Oracle 的 ROWNUM。
在许多情况下,您可以通过在查询中使用 LIMIT 和 OFFSET 来获得相同的结果。

Postgresql does not have an equivalent of Oracle's ROWNUM.
In many cases you can achieve the same result by using LIMIT and OFFSET in your query.

昇り龍 2024-10-04 14:33:05

使用 limit 子句和偏移量来选择行号 -1 所以如果你想获得第 8 行,那么使用:

limit 1 offset 7

use the limit clausule, with the offset to choose the row number -1 so if u wanna get the number 8 row so use:

limit 1 offset 7

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文