Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

EXPORTAR COMO INSTRUÇÕES DE INSERÇÃO:Mas no SQL Plus a linha substitui 2500 caracteres!


Uau, essas restrições são bastante limitantes, mas acho que pode haver uma maneira de contornar isso. Eu acho que você pode ter que escrever seu próprio roteiro para isso.

Eu mesmo usaria Java com JDBC (mas qualquer linguagem que possa se conectar e ler o banco de dados e strings de saída servirá), escrevendo um pequeno programa que recupera um conjunto de registros de cada linha no banco de dados. Então, para cada uma dessas linhas:

  • Construa uma instrução insert com os dados completos. Se isso for menor que 2.000 bytes, basta enviá-lo para o arquivo e passar para a próxima linha.

  • Caso contrário, crie uma instrução de inserção para cada campo, mas deixe o c13 campo como '' (vazio).

  • Então, contanto que seu c13input string for maior que 2000 caracteres, produza uma instrução de atualização no formato "update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..." (anexando os próximos 2.000 caracteres) e então faça c13input = c13input.substring(2000) para retirar esses caracteres da sua string.

  • Uma vez c13input for menor ou igual a 2000 caracteres de comprimento, basta produzir uma atualização final para adicioná-la no final.

Isso permite que você mantenha suas instruções SQL individuais em torno da marca de 2.000 caracteres e execute com eficiência o SQL correto para repovoar outra tabela de banco de dados.

Este é o tipo de coisa que estou falando (para uma tabela contendo apenas uma chave primária c1 e um grande varchar c13 ):
rowset r = db.exec ("select * from oldtable");
while r.next != NO_MORE_ROWS:
    string s = "insert into newtable (c1,c13) values ('" +
        r.get("c1") + "','" + r.get("c13") + "')"
    if s.len() < 2000:
        print s
    else:
        s = "insert into newtable (c1,c13) values ('" + r.get("c1") + "','')"
        print s
        f = r.get("c13")
        while f.len() > 2000:
            s = "update newtable set c13 = c13 || '" + f.substring(0,2000) + ')"
            f = f.substring(2000)
            print s
        endwhile
        s = "update newtable set c13 = c13 || '" + f + ')"
        print s
    endif
endwhile

Obviamente, você pode precisar transformar as strings para permitir inserções de caracteres especiais - não tenho certeza em qual formato o Oracle espera isso, mas espero que seja uma simples questão de passar as strings (r.get("c13") se o comprimento da inserção completa for menor que 2000, f.substring(0,2000) e f se você também estiver construindo atualizações) para uma função auxiliar para fazer isso.

Se for provável que essa transformação aumente o tamanho da linha impressa, você pode querer reduzir o limite de volta para 1000 por segurança, para garantir que a cadeia de caracteres modificada não resulte em uma linha maior que o limite PL/SQL.

Desculpe se isso parece complicado, mas as restrições que você declarou nos prejudicam um pouco. Pode haver uma maneira melhor, mas não consigo pensar em uma que atenda a todos seus critérios.

Atualização: Parece que você é ainda mais paralisado do que se pensava originalmente:se você tiver que se limitar ao SQL para gerar o script, além de executá-lo, existe uma maneira, por mais torturante que seja.

Você pode usar SQL para gerar SQL. Usando minha tabela mencionada com c1 e c13 , você pode fazer:
select
    'insert into newtable (c1,c13) values ("' ||
    c1 ||
    '","");'
from oldtable;
# Xlates to: insert into newtable (c1,c13) values ("[c1]","");

Isso lhe dará toda a sua linha de base insert instruções para duplicar tudo menos o c13 coluna.

O que você precisa fazer é gerar mais instruções para definir c13 . Para atualizar c13 para todos os valores de comprimento 1000 ou menos (conjunto simples):
select
    'update newtable set c13 = "' ||
    c13 ||
    '" where c1 = "' ||
    c1 ||
    '";'
from oldtable where length(c13) <= 1000;
# Xlates to: update newtable set c13 = "[c13]" where c1 = "[c1]";
#   but only for rows where length([c13]) <= 1000

Em seguida, para update c13 para todos os valores entre 1001 e 2000 caracteres (definir e anexar):
select
    'update newtable set c13 = "' ||
    substring(c13,1,1000) ||
    '" where c1 = "' ||
    c1 ||
    '";'
from oldtable where length(c13) > 1000 and length(c13) <= 2000;
select
    'update newtable set c13 = c13 || "' ||
    substring(c13,1001,1000) ||
    '" where c1 = "' ||
    c1 ||
    '";'
from oldtable where length(c13) > 1000 and length(c13) <= 2000;
# Xlates to: update newtable set c13 =        "[c13a]" where c1 = "[c1]";
#            update newtable set c13 = c13 || "[c13b]" where c1 = "[c1]";
#   but only for rows where length([c13]) > 1000 and <= 2000
#   and [c13a]/[c13b] are the first/second thousand chars of c13.

E assim por diante para aqueles que são de 2001 a 3000 e 3001 a 4000 de comprimento.

Provavelmente será necessário fazer alguns ajustes. Fico feliz em dar a você uma maneira de resolvê-lo, mas meu desejo de trabalhar em tal monstruosidade até a conclusão é mínimo na melhor das hipóteses :-)

Será que vai dar conta do trabalho? Sim. É bonito? Eu diria que foi um sonoro "NÃO!" mas, dadas suas limitações, isso pode ser o melhor que você pode esperar.

Como prova de conceito, aqui está um script SQL no DB2 (sem recursos especiais, mas deve funcionar bem em qualquer DBMS que tenha um length e substr equivalente):
# Create table and populate.

DROP TABLE XYZ;
COMMIT;
CREATE TABLE XYZ (F1 VARCHAR(1),F2 VARCHAR(20));
COMMIT;
INSERT INTO XYZ VALUES ('1','PAX');
INSERT INTO XYZ VALUES ('2','GEORGE');
INSERT INTO XYZ VALUES ('3','VLADIMIR');
INSERT INTO XYZ VALUES ('4','ALEXANDRETTA');
SELECT * FROM XYZ ORDER BY F1;

# Create initial insert statem,ents.

SELECT 'INSERT INTO XYZ (F1,F2) VALUES (' || F1 ','''');' 
    FROM XYZ;

# Updates for 1-5 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || F2 ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) <= 5;

# Updates for 6-10 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;

# Updates for 11-15 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
  FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,11) || 
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

e isso gera as seguintes linhas:
> DROP TABLE XYZ;
> COMMIT;
> CREATE TABLE XYZ (F1 VARCHAR(1),F2 VARCHAR(20));
> COMMIT;
> INSERT INTO XYZ VALUES ('1','PAX');
> INSERT INTO XYZ VALUES ('2','GEORGE');
> INSERT INTO XYZ VALUES ('3','VLADIMIR');
> INSERT INTO XYZ VALUES ('4','ALEXANDRETTA');
> SELECT * FROM XYZ;
    F1  F2
    --  ------------
    1   PAX
    2   GEORGE
    3   VLADIMIR
    4   ALEXANDRETTA

> SELECT 'INSERT INTO XYZ (F1,F2) VALUES (' || F1 || ','''');'
> FROM XYZ;
    INSERT INTO XYZ (F1,F2) VALUES (1,'');
    INSERT INTO XYZ (F1,F2) VALUES (2,'');
    INSERT INTO XYZ (F1,F2) VALUES (3,'');
    INSERT INTO XYZ (F1,F2) VALUES (4,'');

> SELECT 'UPDATE XYZ SET F2 = ''' || F2 ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) <= 5;
    UPDATE XYZ SET F2 = 'PAX' WHERE F1 = '1';

> SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;
    UPDATE XYZ SET F2 = 'GEORG' WHERE F1 = '2';
    UPDATE XYZ SET F2 = 'VLADI' WHERE F1 = '3';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;
    UPDATE XYZ SET F2 = F2 || 'E' WHERE F1 = '2';
    UPDATE XYZ SET F2 = F2 || 'MIR' WHERE F1 = '3';

> SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = 'ALEXA' WHERE F1 = '4';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = F2 || 'NDRET' WHERE F1 = '4';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,11) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = F2 || 'TA' WHERE F1 = '4';

Separando as linhas de saída, obtemos:
INSERT INTO XYZ (F1,F2) VALUES (1,'');
INSERT INTO XYZ (F1,F2) VALUES (2,'');
INSERT INTO XYZ (F1,F2) VALUES (3,'');
INSERT INTO XYZ (F1,F2) VALUES (4,'');
UPDATE XYZ SET F2 = 'PAX' WHERE F1 = '1';
UPDATE XYZ SET F2 = 'GEORG' WHERE F1 = '2';
UPDATE XYZ SET F2 = 'VLADI' WHERE F1 = '3';
UPDATE XYZ SET F2 = F2 || 'E' WHERE F1 = '2';
UPDATE XYZ SET F2 = F2 || 'MIR' WHERE F1 = '3';
UPDATE XYZ SET F2 = 'ALEXA' WHERE F1 = '4';
UPDATE XYZ SET F2 = F2 || 'NDRET' WHERE F1 = '4';
UPDATE XYZ SET F2 = F2 || 'TA' WHERE F1 = '4';

que deve fornecer as linhas originais, embora de maneira indireta.

E isso é o máximo de esforço que posso colocar em qualquer pergunta sem meu cérebro fritar, então vou dizer adeus a menos que quaisquer erros sérios sejam apontados para mim.

Boa sorte com seu projeto, e muitas felicidades.