如何检索 oracle 序列的当前值而不增加它?
Posted
技术标签:
【中文标题】如何检索 oracle 序列的当前值而不增加它?【英文标题】:How to retrieve the current value of an oracle sequence without increment it? 【发布时间】:2012-04-29 22:00:00 【问题描述】:是否有一条 SQL 指令可以检索不递增的序列的值。
谢谢。
编辑和结论
正如 Justin Cave 所说,尝试“保存”序列号是没有用的
select a_seq.nextval from dual;
足以检查序列值。
我仍然认为 Ollie 的回答很好,因为它回答了最初的问题。但问问自己是否有必要不修改序列,如果你想这样做。
【问题讨论】:
为什么?您要解决的问题是什么?如果您正确使用序列,则永远不要关心已为其他会话分配了哪些序列值或可能为后续会话分配了哪些值。 数据迁移后的检查,以确保已根据迁移的数据正确更新序列 那么简单地获取序列的nextval
进行测试有什么缺点呢?你不会假设序列是没有间隙的,对吧?所以“浪费”一个序列值应该不是问题。
我想你是对的,我不想为那个检查改变数据库的状态,但老实说我不知道为什么。感谢您的洞察力。不过我确实学到了你关于序列的东西,谢谢大家!
@JustinCave,有一个我正在进行数据迁移的系统,我不知道是否需要无间隙。尽可能少的副作用可以防止我和未来的人可能会追逐红鲱鱼来解决其他问题。
【参考方案1】:
SELECT last_number
FROM all_sequences
WHERE sequence_owner = '<sequence owner>'
AND sequence_name = '<sequence_name>';
您可以从user_sequences
、all_sequences
和dba_sequences
获取各种序列元数据。
这些视图跨会话工作。
编辑:
如果序列在您的默认架构中,则:
SELECT last_number
FROM user_sequences
WHERE sequence_name = '<sequence_name>';
如果您想要所有元数据,那么:
SELECT *
FROM user_sequences
WHERE sequence_name = '<sequence_name>';
希望对你有帮助...
EDIT2:
如果您的缓存大小不是 1,那么一种更可靠的方法是:
SELECT increment_by I
FROM user_sequences
WHERE sequence_name = 'SEQ';
I
-------
1
SELECT seq.nextval S
FROM dual;
S
-------
1234
-- Set the sequence to decrement by
-- the same as its original increment
ALTER SEQUENCE seq
INCREMENT BY -1;
Sequence altered.
SELECT seq.nextval S
FROM dual;
S
-------
1233
-- Reset the sequence to its original increment
ALTER SEQUENCE seq
INCREMENT BY 1;
Sequence altered.
请注意,如果其他人在此期间使用该序列 - 他们(或您)可能会得到 p>
ORA-08004: sequence SEQ.NEXTVAL goes below the sequences MINVALUE and cannot be instantiated
此外,您可能希望在重置之前将缓存设置为 NOCACHE
,然后再将其恢复为原始值,以确保您没有缓存很多值。
【讨论】:
刚刚尝试过,但我无法访问“all_sequences”表。它是只有管理员凭据才能看到的特殊对象吗?ALL_SEQUENCES
是一个视图。如果您无权访问它,请尝试从USER_SEQUENCES
中选择(如果序列在您的默认模式中)。 (USER_SEQUENCES
不需要 sequence_owner = '<sequence_owner>'
子句)。
ALL_SEQUENCES
中的LAST_NUMBER
不会是实际给出会话的最后一个号码,也不会是调用sequence_name.nextval
时返回的号码。假设您已将序列设置为CACHE
超过 1(默认为 20),LAST_NUMBER
将是缓存中的最后一个数字。无法保证这个号码会真正提供给任何会话。
ALTER SEQUENCE seq INCREMENT BY -1;
将成为一个问题,除非可以保证没有其他会话将调用seq.nextval
。否则序列将分发重复值,这通常不是人们想要的。
OP 确实说过“这是数据迁移后的检查”,因此假设数据库不是一般用途并不是一件容易的事,但如果不是这种情况,这可能是一个问题。
【参考方案2】:
select MY_SEQ_NAME.currval from DUAL;
请记住,它仅在您在当前会话中运行 select MY_SEQ_NAME.nextval from DUAL;
时才有效。
【讨论】:
非常感谢您的回答。我必须在 Boomi 内部使用它,并且一直在寻找解决方案【参考方案3】:以下是常用的:
select field_SQ.nextval from dual; -- it will increase the value by 1 for each run
select field_SQ.currval from DUAL;
但是,以下内容能够将顺序更改为您所期望的。 1
可以是整数(负数或正数)
alter sequence field_SQ increment by 1 minvalue 0
【讨论】:
【参考方案4】:这不是一个答案,真的,如果问题没有被锁定,我会输入它作为评论。这回答了这个问题:
你为什么想要它?
假设您有一个以序列作为主键的表,并且该序列是由插入触发器生成的。如果您希望序列可用于记录的后续更新,您需要有一种方法来提取该值。
为了确保获得正确的查询,您可能希望将 INSERT 和 RonK 的查询包装在一个事务中。
RonK 的查询:
select MY_SEQ_NAME.currval from DUAL;
在上述场景中,RonK 的警告不适用,因为插入和更新将发生在同一个会话中。
【讨论】:
【参考方案5】:我还尝试使用 CURRVAL,在我的情况下,以查明是否某个进程以该序列作为主键将新行插入到某个表中。我的假设是 CURRVAL 将是最快的方法。但是 a) CurrVal 不起作用,它只会获得旧值,因为您在另一个 Oracle 会话中,直到您在自己的会话中执行 NEXTVAL。 b) select max(PK) from TheTable
也非常快,可能是因为 PK 总是被索引。或select count(*) from TheTable
。我仍在尝试,但两个 SELECT 似乎都很快。
我不介意序列中的间隙,但就我而言,我一直在考虑进行轮询,并且我讨厌非常大的间隙的想法。特别是如果一个简单的 SELECT 也一样快。
结论:
CURRVAL 非常没用,因为它不会从另一个会话中检测到 NEXTVAL,它只会返回您从之前的 NEXTVAL 中已经知道的内容 SELECT MAX(...) FROM ... 是一个很好的解决方案,简单快速,假设您的序列链接到该表【讨论】:
【参考方案6】:如果您的用例是某些后端代码插入一条记录,那么相同的代码想要检索最后一个插入 id,而不依赖于任何底层数据访问库预设函数来执行此操作,那么,正如其他人所提到的,您应该只使用 SEQ_MY_NAME.NEXTVAL
为您想要的列(通常是主键)制作 SQL 查询,然后从后端运行语句 SELECT SEQ_MY_NAME.CURRVAL FROM dual
。
请记住,CURRVAL 仅在 NEXTVAL 已被事先调用时才可调用,这在上述策略中自然完成...
【讨论】:
这适用于我的用例。因此,无论谁对我投了反对票,都应该以正当的理由详细说明他们的行为……【参考方案7】:我原来的回复实际上是不正确的,我很高兴它被删除了。下面的代码将在以下条件下工作 a) 您知道没有其他人修改过序列 b) 序列已被您的会话修改。在我的例子中,我遇到了一个类似的问题,我正在调用一个修改值的过程,我相信这个假设是正确的。
SELECT mysequence.CURRVAL INTO v_myvariable FROM DUAL;
遗憾的是,如果您没有在会话中修改序列,我相信其他人说 NEXTVAL 是唯一的方法是正确的。
【讨论】:
以上是关于如何检索 oracle 序列的当前值而不增加它?的主要内容,如果未能解决你的问题,请参考以下文章