sql >> Base de Datos >  >> RDS >> Oracle

EXPORTAR COMO INSERTAR DECLARACIONES:¡Pero en SQL Plus la línea anula 2500 caracteres!

Wow, esas restricciones son bastante limitantes, pero creo que puede haber una forma de evitarlo. Creo que es posible que tengas que escribir tu propio pequeño guión para esto.

Yo mismo usaría Java con JDBC (pero cualquier lenguaje que pueda conectarse y leer la base de datos, y cadenas de salida, servirá), escribiendo un pequeño programa que recuperó un conjunto de registros de cada fila en la base de datos. Luego, para cada una de esas filas:

  • Construya una declaración de inserción con los datos completos. Si esto es menos de 2000 bytes, simplemente envíelo al archivo y pase a la siguiente fila.

  • De lo contrario, cree una declaración de inserción para cada campo, pero deje el c13 campo como '' (vacío).

  • Luego, mientras su c13input la cadena tiene más de 2000 caracteres, genera una declaración de actualización de la forma "update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..." (agregando los siguientes 2000 caracteres) y luego c13input = c13input.substring(2000) para eliminar esos caracteres de su cadena.

  • Una vez c13input tiene una longitud menor o igual a 2000 caracteres, solo genera una actualización final para agregarla al final.

Esto le permite mantener sus declaraciones SQL individuales alrededor de la marca de 2000 caracteres y ejecutar eficientemente el SQL correcto para volver a llenar otra tabla de base de datos.

Este es el tipo de cosas de las que estoy hablando (para una tabla que contiene solo una clave principal c1 y un gran varchar que toca la bocina 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, es posible que deba modificar las cadenas para permitir la inserción de caracteres especiales; no estoy seguro de en qué formato los espera Oracle, pero con suerte sería una simple cuestión de pasar las cadenas (r.get("c13") si la longitud de la inserción completa es inferior a 2000, f.substring(0,2000) y f si también está creando actualizaciones) a una función de ayuda para hacer esto.

Si es probable que esa transformación aumente el tamaño de la línea impresa, es posible que desee volver a bajar el umbral a 1000 para estar seguro y asegurarse de que la cadena transformada no resulte en una línea mayor que el límite de PL/SQL.

Lo siento si eso parece enrevesado, pero las restricciones que ha establecido nos paralizan un poco. Bien puede haber una mejor manera, pero no puedo pensar en una que cumpla con todos sus criterios.

Actualizar: Parece que eres incluso más paralizado de lo que se pensó originalmente:si tiene que limitarse a SQL para generar el script además de ejecutarlo, hay una manera, aunque es tortuosa.

Puede usar SQL para generar SQL. Usando mi tabla mencionada anteriormente con c1 y c13 , puedes hacer:

select
    'insert into newtable (c1,c13) values ("' ||
    c1 ||
    '","");'
from oldtable;
# Xlates to: insert into newtable (c1,c13) values ("[c1]","");

Eso le dará toda su referencia insert declaraciones para duplicar todo menos el c13 columna.

Lo que debe hacer entonces es generar más declaraciones para configurar c13 . Para actualizar c13 para todos los valores de longitud 1000 o menos (conjunto simple):

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

Luego, para update c13 para todos los valores entre 1001 y 2000 caracteres (establecer y luego agregar):

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.

Y así sucesivamente para los que tienen una longitud de 2001 a 3000 y de 3001 a 4000.

Es probable que haya que hacer algunos ajustes. Estoy feliz de darle una forma de resolverlo, pero mi deseo de trabajar en tal monstruosidad hasta el final es mínimo en el mejor de los casos :-)

¿Hará el trabajo? Sí. ¿Es bonito? Diría que fue un rotundo "¡NO!" pero, dadas sus limitaciones, eso puede ser lo mejor que puede esperar.

Como prueba de concepto, aquí hay un script SQL en DB2 (aunque no tiene características especiales, debería funcionar bien en cualquier DBMS que tenga una length y 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;

y esto genera las siguientes líneas:

> 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 las líneas de salida, obtenemos:

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

lo que debería darte las filas originales, aunque de forma indirecta.

Y eso es todo el esfuerzo que puedo poner en cualquier pregunta sin que se me fríe el cerebro, así que me despediré a menos que me señalen algún error grave.

Buena suerte con tu proyecto y los mejores deseos.