将序列值从一个Oracle数据库复制到另一个Oracle数据库

将序列值从一个Oracle数据库复制到另一个Oracle数据库,oracle,Oracle,是否可以将模式中序列的当前值复制到另一个数据库?序列已经在两个数据库中创建。这是甲骨文 编辑: 根据下面的帮助,一旦建立了数据库链接,该脚本将确保目标数据库序列值大于或等于源数据库值。这样做的动机是为了在复制数据后不会出现主键错误,因此目标数字不准确这一事实是没有问题的 set serveroutput on DECLARE CURSOR GetCursorsToSync is SELECT a.sequence_name, a.last_number last_number_a,

是否可以将模式中序列的当前值复制到另一个数据库?序列已经在两个数据库中创建。这是甲骨文

编辑:

根据下面的帮助,一旦建立了数据库链接,该脚本将确保目标数据库序列值大于或等于源数据库值。这样做的动机是为了在复制数据后不会出现主键错误,因此目标数字不准确这一事实是没有问题的

set serveroutput on
DECLARE
  CURSOR GetCursorsToSync
  is
  SELECT a.sequence_name, a.last_number last_number_a, b.last_number last_number_b
  FROM user_sequences@SOURCE_DB a, user_sequences b
  where a.sequence_name = b.sequence_name
  and a.last_number != b.last_number;

  type CursorsTableType is table of GetCursorsToSync%rowtype index by pls_integer;  
  CursorsTable  CursorsTableType;
  i             pls_integer;

  PROCEDURE reset_sequence(
      sequence_name IN VARCHAR2,
      source_value  IN NUMBER,
      target_value  IN NUMBER )
  IS
    l_sql varchar2(4000);
    l_temp number(30);
  BEGIN
    IF source_value <= target_value THEN
      RETURN;
    END IF;

    dbms_output.put_line(sequence_name || ' ' || source_value || ' ' || target_value);
    l_sql := 'alter sequence '|| sequence_name || ' increment by '||to_char(source_value-target_value);
    dbms_output.put_line(l_sql);
    EXECUTE immediate l_sql;
    l_sql := 'SELECT '|| sequence_name || '.nextval FROM dual';
    dbms_output.put_line(l_sql);
    EXECUTE immediate l_sql into l_temp;
    dbms_output.put_line(l_temp);
    l_sql := 'alter sequence '|| sequence_name || ' increment by 1';
    dbms_output.put_line(l_sql);
    EXECUTE immediate l_sql;
    COMMIT;
  END reset_sequence;
BEGIN
  open GetCursorsToSync;
  fetch GetCursorsToSync bulk collect into CursorsTable;
  close GetCursorsToSync;
  commit;

  i := CursorsTable.first;
  while i is not null loop
    reset_sequence(CursorsTable(i).sequence_name,
      CursorsTable(i).last_number_a,CursorsTable(i).last_number_b);
    i := CursorsTable.next(i);
  end loop;
end;
/
打开服务器输出
声明
光标GetCursorsToSync
是
选择a.序列号、a.最后一个号码最后一个号码、b.最后一个号码最后一个号码
来自用户_sequences@SOURCE_DBa,用户_序列b
其中a.sequence\u name=b.sequence\u name
还有最后一个号码!=b、 最后一个号码;
类型CursorsTableType是GetCursorsToSync%行类型索引的表,按pls_整型;
可游标可游标类型;
我喜欢整数;
程序复位顺序(
VARCHAR2中的序列名称,
source_的数值,
目标值(以数字表示)
是
l_sql varchar2(4000);
l_临时编号(30);
开始

如果source_value问题:我们如何在Oracle序列中设置LASTVALUE值? 答:您可以通过执行ALTER来更改Oracle序列的LASTVALUE 顺序命令。 例如,如果Oracle序列使用的最后一个值是100,并且您希望重置该序列以用作下一个值。您将执行以下命令

alter sequence seq_name increment by 224;
select seq_name.nextval from dual;
alter sequence seq_name increment by 1;

现在,序列提供的下一个值将是225。

除了可以计划自动运行的存储过程之外,UltraCommits语句和数据库链接的组合将很好地为您服务

--drop create db_link
DROP DATABASE LINK SOURCE_DB;

CREATE DATABASE LINK "SOURCE_DB"
  CONNECT TO USER IDENTIFIED BY password USING 'SOURCE_DB';

 --drop create sequences 
  DROP sequence target_seq;
CREATE sequence target_seq start with 6;

  --the next two lines run in source db
  DROP sequence source_seq;
CREATE sequence source_seq start with 6000;

--take a look at the sequences to get an idea of what to expect
SELECT source_schema.source_seq.nextval@SOURCE_DB source_seq,
  target_seq.nextval target_seq
FROM dual; 

--create procedure to reset target sequence that you can schedule to automatically run
CREATE OR REPLACE
PROCEDURE reset_sequence
AS
  l_source_sequence pls_integer;
  l_target_sequence pls_integer;
  l_sql VARCHAR2(100);
BEGIN
  SELECT source_schema.source_seq.nextval@SOURCE_DB,
    target_seq.nextval
  INTO l_source_sequence,
    l_target_sequence
  FROM dual;
  l_sql := 'alter sequence target_seq increment by '||to_number(l_source_sequence-l_target_sequence);
  EXECUTE immediate l_sql;
  SELECT target_seq.nextval INTO l_target_sequence FROM dual;
  l_sql := 'alter sequence target_seq increment by 1';
  EXECUTE immediate l_sql;
  COMMIT;
END reset_sequence;
/

--execute procedure to test it out
EXECUTE reset_sequence;

--review results; should be the same
SELECT source_schema.source_seq.nextval@SOURCE_DB, target_seq.nextval FROM dual;

我在尝试执行基于Reynold先生提供的脚本时遇到以下错误:

ORA-04013:要缓存的数字必须少于一个周期。

原因:要缓存的给定数量大于一个周期中的值。 操作:放大循环,或缓存较少的值

如果当前nextval太大,无法在当前周期中缓存指定数量的值,则会遇到此错误。因此,我包含了他的脚本的更新版本,其中首先使用“NOCACHE”选项更改目标序列,然后在更新目标nextval后将缓存恢复为其原始值。在我的示例中,db链接和别名“PD”表示源数据库,“QA”表示目标数据库

我希望这对其他人有帮助,就像之前的解决方案对我一样

SET serveroutput ON
DECLARE
   CURSOR GetCursorsToSync IS
   SELECT pd.sequence_name, pd.last_number last_number_pd,
          qa.last_number last_number_qa, qa.cache_size
     FROM user_sequences@PD pd
     JOIN user_sequences qa
       on qa.sequence_name = pd.sequence_name
    WHERE qa.last_number != pd.last_number;

   TYPE CursorsTableType IS
   TABLE OF GetCursorsToSync%ROWTYPE INDEX BY pls_integer;  
      CursorsTable  CursorsTableType;
      i             pls_integer;

   PROCEDURE Reset_Sequence(
      sequence_name IN VARCHAR2,
      source_value  IN NUMBER,
      target_value  IN NUMBER,
      cache_size    IN NUMBER)
   IS
      l_sql    VARCHAR2(4000);
      l_temp   NUMBER(30);
   BEGIN
      IF source_value <= target_value THEN
         RETURN;
      END IF;

      dbms_output.put_line(sequence_name || ' ' || source_value || ' ' || target_value);
      IF cache_size > 0 THEN
         l_sql := 'alter sequence '|| sequence_name || ' nocache';
         dbms_output.put_line(l_sql);
         EXECUTE IMMEDIATE l_sql;
      END IF;

      l_sql := 'alter sequence '|| sequence_name || ' increment by ' || TO_CHAR(source_value-target_value);
      dbms_output.put_line(l_sql);
      EXECUTE IMMEDIATE l_sql;

      l_sql := 'SELECT ' || sequence_name || '.nextval FROM dual';
      dbms_output.put_line(l_sql);
      EXECUTE IMMEDIATE l_sql INTO l_temp;

      dbms_output.put_line(l_temp);

      l_sql := 'alter sequence ' || sequence_name || ' increment by 1';
      dbms_output.put_line(l_sql);
      EXECUTE IMMEDIATE l_sql;

      IF cache_size > 0 THEN
         l_sql := 'alter sequence '|| sequence_name || ' cache ' || TO_CHAR(cache_size);
         dbms_output.put_line(l_sql);
         EXECUTE IMMEDIATE l_sql;
      END IF;

      COMMIT;
   END Reset_Sequence;

BEGIN
   OPEN GetCursorsToSync;
   FETCH GetCursorsToSync BULK COLLECT INTO CursorsTable;
   CLOSE GetCursorsToSync;
   COMMIT;

   i := CursorsTable.FIRST;
   WHILE i IS NOT NULL LOOP
      Reset_Sequence(CursorsTable(i).sequence_name, CursorsTable(i).last_number_pd,
         CursorsTable(i).last_number_qa, CursorsTable(i).cache_size);
      i := CursorsTable.NEXT(i);
   END LOOP;
END;
/
打开服务器输出
声明
光标GetCursorsToSync为
选择pd.sequence\U name、pd.last\U number last\U number\U pd、,
qa.last_编号last_编号qa,qa.cache_大小
来自用户_sequences@PDpd
加入用户程序
关于qa.sequence\u name=pd.sequence\u name
qa.last_编号在哪里!=pd.最后一个_编号;
类型CursorsTableType为
按pls_整数计算的GetCursorsToSync%行类型索引表;
可游标可游标类型;
我喜欢整数;
程序复位顺序(
VARCHAR2中的序列名称,
source_的数值,
目标值的数量,
缓存大小(以数字表示)
是
l_sql VARCHAR2(4000);
l_临时编号(30);
开始
如果源_值为0,则
l|u sql:=“alter sequence”| sequence|u name | nocache”;
dbms_output.put_line(l_sql);
执行即时l_sql;
如果结束;
l|sql:=“alter sequence”| | sequence| U name | |递增“| |到_CHAR(源|值-目标|值);
dbms_output.put_line(l_sql);
执行即时l_sql;
l|U sql:='选择'| |序列| | |'。从双变量选择下一个变量';
dbms_output.put_line(l_sql);
在l_temp中执行即时l_sql;
dbms_输出。输入线(l_温度);
l|U sql:=“改变顺序”|顺序|名称| |“增加1”;
dbms_output.put_line(l_sql);
执行即时l_sql;
如果缓存大小>0,则
l|U sql:=“改变序列”|序列|名称| |“缓存”| |为_字符(缓存|大小);
dbms_output.put_line(l_sql);
执行即时l_sql;
如果结束;
犯罪
结束复位序列;
开始
打开GetCursorsToSync;
获取GetCursorsToSync批量收集到CursorsTable中;
关闭GetCursorsToSync;
犯罪
i:=游标表1;
而我不是空循环
重置顺序(游标表(i)。顺序名称,游标表(i)。最后一个编号,
游标表(i).最后的游标编号(qa),游标表(i).缓存大小);
i:=游标表。下一步(i);
端环;
结束;
/

是的,但这是每个序列的手动过程,我真正想要的是一些自动化的方法。我们能假设数据库之间存在数据库链接吗?看起来不错,谢谢。然后我想我可以把它总结成一个过程来获取模式中的所有序列并将它们转移。我根据你的建议编辑了我的问题,以合并我的过程。再次感谢。可能值得考虑在源数据库进程中使用db_链接和目标数据库中的序列,而不是在两个数据库中使用相同的序列。这基本上是将数据从一个数据库播种到另一个数据库,因此我不希望在此进程之后连接它们。
--
-- Procedure to replicate the value of sequences from source to destination schema
--
-- The database link name must be PROD
--
-- SQL> CREATE DATABASE LINK PROD CONNECT TO ...
--
CREATE OR REPLACE PROCEDURE RESET_SEQUENCES
AS
    CURSOR CSEQUENCES
    IS
    SELECT   SEQUENCE_NAME
    FROM     USER_SEQUENCES@PROD;

    L_SEQUENCE_NAME     USER_SEQUENCES.SEQUENCE_NAME%TYPE;
    L_SRC_SEQ_VALUE     USER_SEQUENCES.MAX_VALUE%TYPE;
    L_DST_SEQ_VALUE     USER_SEQUENCES.MAX_VALUE%TYPE;

    L_SQL VARCHAR2(200);

BEGIN

    OPEN CSEQUENCES;

    LOOP

        FETCH CSEQUENCES INTO L_SEQUENCE_NAME;
        EXIT WHEN CSEQUENCES%NOTFOUND;
        --
        -- Select sequence value from source schema
        --
        L_SQL := 'SELECT '|| L_SEQUENCE_NAME ||'.NEXTVAL@PROD FROM DUAL';

        EXECUTE IMMEDIATE L_SQL INTO L_SRC_SEQ_VALUE;
        --
        -- Select sequence value from destination schema
        --
        L_SQL := 'SELECT '|| L_SEQUENCE_NAME ||'.NEXTVAL FROM DUAL';

        EXECUTE IMMEDIATE L_SQL INTO L_DST_SEQ_VALUE;

        DBMS_OUTPUT.PUT_LINE('SEQUENCE_NAME: '||L_SEQUENCE_NAME);
        DBMS_OUTPUT.PUT_LINE('::BEFORE => SRC VALUE: '||L_SRC_SEQ_VALUE||' DST VALUE: '||L_DST_SEQ_VALUE);

        --
        -- Synchronize sequences value, only if necessary
        --
        IF L_SRC_SEQ_VALUE > L_DST_SEQ_VALUE THEN
            --
            -- Alter increment by to diference between L_SRC_SEQ_VALUE and L_DST_SEQ_VALUE
            --
            L_SQL := 'ALTER SEQUENCE '|| L_SEQUENCE_NAME ||' INCREMENT BY '||TO_CHAR(L_SRC_SEQ_VALUE-L_DST_SEQ_VALUE);

            EXECUTE IMMEDIATE L_SQL;
            --
            -- Select sequence value
            --
            L_SQL := 'SELECT '|| L_SEQUENCE_NAME ||'.NEXTVAL FROM DUAL';

            EXECUTE IMMEDIATE L_SQL INTO L_DST_SEQ_VALUE;
            --
            -- Alter increment by back to 1
            --
            L_SQL := 'ALTER SEQUENCE '|| L_SEQUENCE_NAME ||' INCREMENT BY 1';

            EXECUTE IMMEDIATE L_SQL;

        END IF;

        DBMS_OUTPUT.PUT_LINE('::AFTER  => SRC VALUE: '||L_SRC_SEQ_VALUE||' DST VALUE: '||L_DST_SEQ_VALUE);

    END LOOP;

    CLOSE CSEQUENCES;

END RESET_SEQUENCES;
/

--
-- EXECUTE RESET_SEQUENCES PROCEDURE AND BE HAPPY!
--
SQL> EXEC RESET_SEQUENCES