有什么方法可以在 postgresql 中模拟 rownum 吗?
8 回答
PostgreSQL > 8.4
SELECT
row_number() OVER (ORDER BY col1) AS i,
e.col1,
e.col2,
...
FROM ...
Postgresql 有限制。
甲骨文的代码:
select *
from
tbl
where rownum <= 1000;
在 Postgresql 的代码中相同:
select *
from
tbl
limit 1000
我刚刚在 Postgres 9.1 中测试了一个接近 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;
您可以将 order by 添加到 inline_v1 SQL,以便您的 ROWNUM 对您的数据具有一定的顺序意义。
select nextval('temp_seq') as ROWNUM, c1
from sometable
ORDER BY c1 desc;
可能不是最快的,但如果您确实需要它们,这是一个选择。
如果您有唯一的密钥,您可以使用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 |
Postgresql 没有相当于 Oracle 的 ROWNUM。在许多情况下,您可以通过在查询中使用 LIMIT 和 OFFSET 来获得相同的结果。
我认为可以使用临时序列来模仿 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() 是 volatile 并且每次都由 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() over () 与 nextval)
使用限制子句,使用偏移量选择行号 -1 所以如果你想获得第 8 行,那么使用:
限制 1 偏移量 7