如何在一个查询中两次选择相同的序列?
我已经用谷歌搜索了这个,但无法得到答案。
为了清楚起见,这就是我需要的,例如:
select seq.nextval as v1, seq.nextval as v2 from dual
(我知道这行不通)
我也尝试过 UNION,只是无法理解它。
如果您总是需要两个值,您可以将序列更改为以 2 为增量:
alter sequence seq increment by 2;
然后选择当前值及其后继值:
select seq.nextval,
seq.nextval + 1
from dual;
不漂亮,但它应该做的工作。
更新
只是为了澄清:ALTER SEQUENCE
一生中应该只发布一次,而不是每个会话一次!
弗兰克的答案有一个缺点:
您不能在事务系统中使用它,因为 ALTER SEQUENCE 提交任何未决的 DML。
肖恩的答案只拉序列一次。据我了解,您想提取两个值。作为 Seans 解决方案的替代方案,您还可以从 .nextval 中选择两次,因为 ORACLE 会两次为您提供相同的值。
我更喜欢将序列包装在一个过程中。这会欺骗 oracle 将序列拉两次。
CREATE or replace FUNCTION GetSeq return number as
nSeq NUMBER;
begin
select seq.nextval into nSeq from dual;
return nSeq;
end;
/
如果你一般需要这个,也许你会喜欢:
CREATE or replace FUNCTION GetSeq(spSeq in VARCHAR2) return number as
nSeq NUMBER;
v_sql long;
begin
v_sql:='select '||upper(spSeq)||'.nextval from dual';
execute immediate v_sql into nSeq;
return nSeq;
end;
/
如何使用有一些限制NEXTVAL
。Oracle 文档中有一个列表。更重要的是,该链接包含一个条件列表,其中 NEXTVAL 将被多次调用。
页面上指定的唯一一个直接 SELECT 将NEXTVAL
多次调用的场景是在"A top-level SELECT statement"中。将调用NEXTVAL
两次的粗略查询是:
SELECT seq.NEXTVAL FROM (
SELECT * FROM DUAL
CONNECT BY LEVEL <= 2) -- Change the "2" to get more sequences
不幸的是,如果您尝试将其推送到子查询中以将值展平为具有列的一行v1
并且v2
(就像您的问题一样),您将获得ORA-02287: sequence number not allowed here
.
这是我能得到的最接近的。如果上面的查询不能帮助您到达您想要的位置,请查看此处发布的其他答案。当我一直在打字时,已经发布了几个很好的答案。
告诉你多次调用 sequence.nextval 会很无聊,所以你可以尝试以下方法:
create type t_num_tab as table of number;
CREATE SEQUENCE SEQ_TEST
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
CACHE 100
NOORDER;
create or replace function get_seq_vals(i_num in number) return t_num_tab is
seq_tab t_num_tab;
begin
select SEQ_TEST.nextval
bulk collect into seq_tab
from all_objects
where rownum <= i_num;
return seq_tab;
end;
您可以按如下方式使用它。此示例从序列中一次提取 7 个数字:
declare
numbers t_num_tab;
idx number;
begin
-- this grabs x numbers at a time
numbers := get_seq_vals(7);
-- this just loops through the returned numbers
-- to show the values
idx := numbers.first;
loop
dbms_output.put_line(numbers(idx));
idx := numbers.next(idx);
exit when idx is null;
end loop;
end;
另请注意,我使用“next”而不是 first..last,因为您可能希望在迭代之前从列表中删除数字(或者,有时序列缓存可能导致数字增加超过 1)。