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

时间:2011-06-21 11:13:55

标签: oracle

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

编辑:

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

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;
/

4 个答案:

答案 0 :(得分:4)

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;

答案 1 :(得分:0)

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

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

现在,序列服务的下一个值将是225。

答案 2 :(得分:0)

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

ORA-04013:CACHE的编号必须少于一个周期。

原因:给定CACHE的数量大于循环中的值。 行动:扩大周期,或缓存更少的值。

如果当前 nextval 太大而无法在当前周期中缓存指定数量的值,则会遇到此错误。因此,我已经包含了他的脚本的更新版本,其中首先使用“NOCACHE”选项更改目标序列,然后在更新目标 nextval 之后将缓存恢复为其原始值。在我的示例中,db-link和别名“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;
/

答案 3 :(得分:0)

myFile