Pergunta

Eu gostaria de gerar inserir-cordas para uma linha no meu banco de dados Oracle, incluindo todas as suas linhas dependentes em outras tabelas (e suas linhas dependentes).

Exemplo:

CREATE TABLE a (
  a_id number PRIMARY KEY,
  name varchar2(100)
);
CREATE TABLE b (
  b_id number PRIMARY KEY,
  a_id number REFERENCES a(a_id)
);

Quando eu extrair a linha de uma com A_ID = 1, o resultado deve ser uma string de inserção para que as linhas de linha e dependentes:

INSERT INTO a(a_id, name) VALUES (1, 'foo');
INSERT INTO b(b_id, a_id) VALUES (1, 1);
INSERT INTO b(b_id, a_id) VALUES (2, 1);
INSERT INTO b(b_id, a_id) VALUES (3, 1);

A razão pela qual eu quero fazer isso é, que tenho grande banco de dados com muitas mesas e restrições diferentes entre então e eu gostaria de extrair um pequeno subconjunto de dados como dados de teste.

Foi útil?

Solução

Pode haver alguma ferramenta que faz isso já, mas para extrair arbitrariamente todas as linhas mesas de uma tabela inicial é uma tarefa de desenvolvimento pequena em si. Eu não posso escrever a coisa toda para você, mas eu posso começar -. Comecei a escrevê-lo, mas após cerca de 20 minutos, eu percebi que era um pouco mais de trabalho que eu quis se comprometer com uma resposta não pago

Eu posso ver isso sendo feito melhor por um recursiva PL / SQL procedimento que usaria dbms_ouput e USER_CONS_COLUMNS & user_constraints para criar inserções declaração para a tabela de origem. Você pode enganar um pouco por escrito todas as inserções como se as colunas eram valores de char, desde que a Oracle irá converter implicitamente quaisquer valores CHAR para o tipo de dados para a direita, assumindo seus parâmetros NLS são idênticos no sistema de origem e de destino.

Note, o pacote abaixo terá problemas se você tiver relações circulares em suas mesas; também, em versões anteriores do Oracle, você pode funcionar fora de tampão espaço com DBMS_OUTPUT. Ambos os problemas podem ser resolvidos através da inserção do sql gerado em uma tabela de preparação que tem um índice exclusivo na sql, e abortar a recursão se você receber uma colisão chave única. O grande economia de tempo a seguir é a função MakeParamList, que converte um cursor que retorna uma lista de colunas em qualquer uma vírgula lista, ou uma única expressão que irá apresentar os valores de estas colunas em uma citado separados, separados por vírgulas forma quando executado como o selecionar cláusula em uma consulta contra a tabela.

Note também que o seguinte pacote não vai realmente funcionar até que você modificá-lo ainda mais (uma das razões que eu parei de escrever isso): A instrução de inserção inicial gerada é baseada no pressuposto de que o argumento constraint_vals aprovada em resultará em uma única linha que está sendo gerado - claro, isso é quase certamente não é o caso quando você começar a recursão (desde que você terá muitas linhas filho para um pai). Você vai precisar alterar a geração da primeira declaração (e os subseqüentes chamadas recursivas) estar dentro de um loop para lidar com os casos em que a chamada para a chamada IMEDIATA primeira EXECUTAR gera várias linhas em vez de uma única. As noções básicas de fazê-lo funcionar aqui, você só precisa moer os detalhes e começar o trabalho cursor externo.

Uma nota final também: É improvável que você pode executar este procedimento para gerar um conjunto de linhas que, quando inserida em um sistema de destino, resultariam em uma configuração "limpa" de dados, uma vez que, embora você teria todos dependentes dados, que os dados podem depender de outras tabelas que você não importar (por exemplo, a primeira tabela filho que você encontrar pode ter outras chaves estrangeiras que apontam para tabelas não relacionadas à sua mesa inicial). Nesse caso, você pode querer começar com as tabelas de detalhes e sua maneira de trabalhar, em vez de para baixo; Fazendo isso, você também iria querer inverter a ordem para as declarações que você gerados, ou usando um utilitário de scripting, ou através da inserção do sql em uma tabela de preparação como eu mencionei acima, com uma seqüência, em seguida, selecionando-a com uma espécie descendente .

Como para invocá-lo, você passa a vírgula lista de colunas separadas para restringir como constraint_cols ea vírgula correspondente lista de valores como constraint_vals, por exemplo separados:.

exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')

Aqui está:

CREATE OR REPLACE PACKAGE data_extractor
IS
   TYPE column_info IS RECORD(
      column_name   user_tab_columns.column_name%TYPE
   );

   TYPE column_info_cursor IS REF CURSOR
      RETURN column_info;

   FUNCTION makeparamlist(
      column_info   column_info_cursor
    , get_values    NUMBER
   )
      RETURN VARCHAR2;

   PROCEDURE makeinserts(
      source_table      VARCHAR2
    , constraint_cols   VARCHAR2
    , constraint_vals   VARCHAR2
   );
END data_extractor;


CREATE OR REPLACE PACKAGE BODY data_extractor
AS
   FUNCTION makeparamlist(
      column_info   column_info_cursor
    , get_values    NUMBER
   )
      RETURN VARCHAR2
   AS
   BEGIN
      DECLARE
         column_name   user_tab_columns.column_name%TYPE;
         tempsql       VARCHAR2(4000);
         separator     VARCHAR2(20);
      BEGIN
         IF get_values = 1
         THEN
            separator := ''''''''' || ';
         ELSE
            separator := '';
         END IF;

         LOOP
            FETCH column_info
             INTO column_name;

            EXIT WHEN column_info%NOTFOUND;
            tempsql := tempsql || separator || column_name;

            IF get_values = 1
            THEN
               separator := ' || '''''', '''''' || ';
            ELSE
               separator := ', ';
            END IF;
         END LOOP;

         IF get_values = 1
         THEN
            tempsql := tempsql || ' || ''''''''';
         END IF;

         RETURN tempsql;
      END;
   END;

   PROCEDURE makeinserts(
      source_table      VARCHAR2
    , constraint_cols   VARCHAR2
    , constraint_vals   VARCHAR2
   )
   AS
   BEGIN
      DECLARE
         basesql               VARCHAR2(4000);
         extractsql            VARCHAR2(4000);
         tempsql               VARCHAR2(4000);
         valuelist             VARCHAR2(4000);
         childconstraint_vals  VARCHAR2(4000);
      BEGIN
         SELECT makeparamlist(CURSOR(SELECT column_name
                                       FROM user_tab_columns
                                      WHERE table_name = source_table), 0)
           INTO tempsql
           FROM DUAL;

         basesql := 'INSERT INTO ' || source_table || '(' || tempsql || ') VALUES (';

         SELECT makeparamlist(CURSOR(SELECT column_name
                                       FROM user_tab_columns
                                      WHERE table_name = source_table), 1)
           INTO tempsql
           FROM DUAL;

         extractsql := 'SELECT ' || tempsql || ' FROM ' || source_table 
                       || ' WHERE (' || constraint_cols || ') = (SELECT ' 
                       || constraint_vals || ' FROM DUAL)';

         EXECUTE IMMEDIATE extractsql
                      INTO valuelist;

         -- This prints out the insert statement for the root row
         DBMS_OUTPUT.put_line(basesql || valuelist || ');');

         -- Now we construct the constraint_vals parameter for subsequent calls:
         SELECT makeparamlist(CURSOR(  SELECT column_name
                                         FROM user_cons_columns ucc
                                            , user_constraints uc
                                        WHERE uc.table_name = source_table
                                          AND ucc.constraint_name = uc.constraint_name
                                     ORDER BY position)
                             , 1)
           INTO tempsql
           FROM DUAL;

         extractsql := 'SELECT ' || tempsql || ' FROM ' || source_table 
                       || ' WHERE ' || constraint_cols || ' = ' || constraint_vals;

         EXECUTE IMMEDIATE extractsql
                      INTO childconstraint_vals;

         childconstraint_vals := childconstraint_vals;

-- Now iterate over the dependent tables for this table
-- Cursor on this statement:
--    SELECT uc.table_name child_table, uc.constraint_name fk_name
--      FROM user_constraints uc
--         , user_constraints ucp
--     WHERE ucp.table_name = source_table
--      AND uc.r_constraint_name = ucp.constraint_name;

         --   For each table in that statement, find the foreign key 
         --   columns that correspond to the rows
         --   in the parent table
         --  SELECT column_name
         --    FROM user_cons_columns
         --   WHERE constraint_name = fk_name
         --ORDER BY POSITION;

         -- Pass that columns into makeparamlist above to create 
         -- the constraint_cols argument of the call below:

         -- makeinserts(child_table, ChildConstraint_cols, childconstrain_vals);
      END;
   END;
END data_extractor;

Outras dicas

Eu só uso simples SQL velho para fazer essas tarefas - use as instruções de seleção para gerar suas inserções:

set pagesize 0
set verify off

  SELECT 'INSERT INTO a(a_id, name) VALUES ('
         || a_id || ', '
         || '''' || name || ''');'
    FROM a
   WHERE a_id = &&1;

  SELECT 'INSERT INTO b(b_id, a_id) VALUES ('
         || b_id || ', '
         || a_id || ');'
    FROM b
   WHERE a_id = &&1;

Eu acho DBUnit pode fazer isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top