oracle 如何检查数据库Sequencer是否与数据库记录中的最高当前值同步

hl0ma9xz  于 2023-10-16  发布在  Oracle
关注(0)|答案(2)|浏览(97)

我需要确定Sequencer的当前值是否与特定ID列的最高值同步。举例来说:

Records | ID
-------------
record1   1
record2   2
record3   7
record4   13

如果测序仪的CURRVAL为13,则通过
如果序列器的CURRVAL为其他值(如1、5或18),则为FAIL
我想这样做的方式是将max(ID)与SEQ.CURRVAL进行比较,但下面的代码不起作用:

SELECT COUNT(*) AS n
FROM "MY_SCHEMA"."MY_TABLE" p
WHERE "MY_SCHEMA"."MY_SEQUENCE".CURRVAL = max(p.id);

如果一切都是同步的,我应该得到一个值“1”
否则,失败是值“0”
代码失败,并出现以下错误:

ORA-00934: group function is not allowed here
00934. 00000 -  "group function is not allowed here"
*Cause:    
*Action:
Error at Line: 3 Column: 62

我也试过下面的代码:

SELECT COUNT(*) AS n
FROM "LOGMODGCSS_DATA"."SUFFIX_ITEMS" p
HAVING "LOGMODGCSS_DATA"."SUFFIX_ITEMS_SEQ".CURRVAL = max(id);

使用HAVING子句,我可以绕过第一个错误,但要知道我有以下错误:

ORA-02287: sequence number not allowed here
02287. 00000 -  "sequence number not allowed here"
*Cause:    The specified sequence number (CURRVAL or NEXTVAL) is inappropriate
           here in the statement.
*Action:   Remove the sequence number.
Error at Line: 3 Column: 45

有没有一种方法可以用常规的SQL(最好是一行程序)来实现这一点?

wfsdck30

wfsdck301#

我不确定你能做到这一点,不是单行查询,不是多行查询,也不是PL/SQL。我希望看到一个演示,证明我错了(这将意味着我会学到一些新的东西)。
这就是为什么我认为我所说的。
首先,你不能选择当前序列值,除非它在当前会话中被初始化。
我有一个测试表(包含一些ID)和一个名为SEQ的序列。
最后一个ID值:

SQL> select max(id) From test;

   MAX(ID)
----------
        10

“最后”序列值:

SQL> select seq.currval from dual;
select seq.currval from dual
       *
ERROR at line 1:
ORA-08002: sequence SEQ.CURRVAL is not yet defined in this session

SQL>

这意味着你首先必须选择nextval,这样你就可以选择currval,但是-你已经知道了(这就是你刚刚选择的nextval,不是吗?):

SQL> select seq.nextval from dual;

   NEXTVAL
----------
        27

SQL> select seq.currval from dual;

   CURRVAL
----------
        27

SQL>

然而,这意味着你已经破坏了表和序列之间的同步,因为你使用了序列值,而没有对表本身做任何事情,所以是你做的,只是通过检查序列值。
此外,你得到的错误与aggregate(max)函数的无效使用有关-你应该把它放在having子句中(但这也是无效的):

SQL> select count(*)
  2  from test
  3  having max(id) = (select seq.nextval from dual);
having max(id) = (select seq.nextval from dual)
                             *
ERROR at line 3:
ORA-02287: sequence number not allowed here

SQL>

如果你想使用数据字典,你可以:

SQL> select last_number from user_sequences where sequence_name = 'SEQ';

LAST_NUMBER
-----------
         43

SQL>

这远远超出了当前值--我相信这是因为缓存(在创建序列时可以设置缓存,但由于我已经描述过的原因--选择nextval会破坏它)。
如果你想到PL/SQL:

SQL> set serveroutput on;
SQL> declare
  2    l_max_id test.id%type;
  3    l_seq    number;
  4  begin
  5    select max(id) into l_max_id from test;
  6    select seq.nextval into l_seq from dual;
  7
  8    if l_max_id = l_seq then
  9       dbms_output.put_line('Max ID = ' || l_max_id ||', SEQ = ' || l_seq || ' - match');
 10    else
 11       dbms_output.put_line('Max ID = ' || l_max_id ||', SEQ = ' || l_seq || ' - no match');
 12    end if;
 13  end;
 14  /
Max ID = 10, SEQ = 29 - no match

PL/SQL procedure successfully completed.

SQL>
  • 也许 * 你可以获取序列,将它与存储在表中的最大ID值进行比较,然后改变序列以 * 减少 * 它的值,这样它看起来就像什么都没有发生。但是,如果只有您使用该序列,则可能没有问题。如果有许多用户,他们都插入了许多行,并且有一个数据库触发器设置了ID值,该怎么办?正确设置最后一个序列值将变得 * 不可能 *。夜间工作?可能吧,说不准。

另一方面,你为什么关心?序列将确保您具有唯一的值。可能会有(而且很可能会有)间隙,因为你可能选择nextval,插入到一个表中,然后回滚-你会使用序列值,而你在同一时刻不同步。或许你应该接受你无法影响它的事实。
[编辑]**
如果你担心序列会导致重复,如果表已经包含序列还没有达到的值,修复序列-很容易。
我在表中插入了更大的ID来说明它:

SQL> select max(id) From test;

   MAX(ID)
----------
       500

SQL> select seq.nextval from dual;

   NEXTVAL
----------
        30

MAX ID与最后一个序列值之差的递增序列(500 - 30 = 470):

SQL> alter sequence seq increment by 470;

Sequence altered.

SQL> select seq.nextval from dual;

   NEXTVAL
----------
       500

将其设置为递增1,就完成了:

SQL> alter sequence seq increment by 1;

Sequence altered.

SQL> select seq.nextval from dual;

   NEXTVAL
----------
       501

SQL>
pn9klfpd

pn9klfpd2#

只是一个评论,我有类似的要求。对于一个应用程序,我不得不每年复制1-2次某些表的生产数据到测试系统。之后,TEST系统的序列值与表中的数据不“同步”。因此,我必须开发一个PL/SQL脚本来检查表的最高值与序列的当前值。之后,序列被动态地“改变”为再次“同步”。

相关问题