Скопируйте значения последовательности из одной базы данных Oracle в другую - PullRequest
4 голосов
/ 21 июня 2011

Можно ли скопировать текущие значения последовательностей в схеме в другую базу данных? Последовательности уже созданы в обеих базах данных. Это в Oracle.

Edit:

Исходя из приведенной ниже справки, после настройки ссылки на базу данных этот сценарий будет обеспечивать, чтобы значения последовательности целевой базы данных были больше или равны значениям исходной базы данных. Это объясняется тем, что мы не получаем ошибок первичного ключа после копирования данных, поэтому тот факт, что целевые числа не являются точными, не является проблемой.

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 ]

4 голосов
/ 21 июня 2011

Комбинация операторов 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;
0 голосов
/ 01 июня 2016
--
-- 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
0 голосов
/ 10 марта 2014

Я столкнулся со следующей ошибкой при попытке выполнить скрипт на основе скрипта, предоставленного мистером Рейнольдом:

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;
/
0 голосов
/ 21 июня 2011

Вопрос: Как установить значение LASTVALUE в последовательности Oracle?Ответ: Вы можете изменить LASTVALUE для последовательности Oracle, выполнив команду ALTER 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...