Oracle
 sql >> Database >  >> RDS >> Oracle

ESPORTA COME DICHIARAZIONI INSERT:Ma in SQL Plus la riga sovrascrive 2500 caratteri!

Wow, questi vincoli sono piuttosto limitanti, ma penso che potrebbe esserci un modo per aggirarlo. Penso che potresti dover scrivere la tua piccola sceneggiatura per questo.

Io stesso userei Java con JDBC (ma qualsiasi linguaggio in grado di connettersi e leggere il database e le stringhe di output, lo farà), scrivendo un piccolo programma che ha recuperato un set di record di ogni riga nel database. Quindi, per ognuna di queste righe:

  • Costruisci un'istruzione di inserimento con i dati completi. Se questo è inferiore a 2.000 byte, invialo semplicemente al file e passa alla riga successiva.

  • Altrimenti crea un'istruzione di inserimento per ogni campo, ma lascia il c13 campo come '' (vuoto).

  • Quindi, purché il tuo c13input la stringa è maggiore di 2000 caratteri, genera un'istruzione di aggiornamento nel formato "update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..." (aggiungendo i successivi 2000 caratteri) e quindi esegui c13input = c13input.substring(2000) per rimuovere quei caratteri dalla tua stringa.

  • Una volta c13input ha una lunghezza inferiore o uguale a 2000 caratteri, basta produrre un aggiornamento finale per modificarlo alla fine.

Ciò ti consente di mantenere le tue singole istruzioni SQL attorno al segno di 2000 caratteri ed eseguire in modo efficiente l'SQL corretto per ripopolare un'altra tabella del database.

Questo è il tipo di cosa di cui sto parlando (per una tabella contenente solo una chiave primaria c1 e un grande clacson 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

Ovviamente, potrebbe essere necessario modificare le stringhe per consentire l'inserimento di caratteri speciali:non sono sicuro del formato in cui Oracle si aspetta questi, ma si spera che sia una semplice questione di passare le stringhe (r.get("c13") se la lunghezza dell'intero inserto è inferiore a 2000, f.substring(0,2000) e f se stai costruendo anche gli aggiornamenti) a una funzione di supporto per farlo.

Se è probabile che il morphing aumenti la dimensione della riga stampata, potresti voler ridurre la soglia a 1000 per sicurezza, per assicurarti che la stringa modificata non risulti in una riga maggiore del limite PL/SQL.

Scusa se sembra contorto, ma le restrizioni che hai dichiarato ci ostacolano un po'. Potrebbe esserci un modo migliore, ma non riesco a pensare a uno che soddisfi tutti i tuoi criteri.

Aggiornamento: Sembra che tu sia ancora di più ostacolato di quanto inizialmente pensato:se devi limitarti a SQL per generare lo script oltre a eseguirlo, c'è un modo, per quanto tortuoso sia.

È possibile utilizzare SQL per generare SQL. Usando la mia suddetta tabella con c1 e c13 , puoi fare:

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

Questo ti darà tutti i tuoi insert di base istruzioni per duplicare tutto tranne il c13 colonna.

Quello che devi fare è generare più istruzioni per impostare c13 . Per aggiornare c13 per tutti i valori di lunghezza 1000 o inferiore (set semplice):

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

Quindi, per update c13 per tutti i valori compresi tra 1001 e 2000 caratteri (impostare quindi aggiungere):

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 così via per quelli che hanno una lunghezza compresa tra 2001 e 3000 e tra 3001 e 4000.

Probabilmente sarà necessario apportare alcune modifiche. Sono felice di darti un modo per risolverlo, ma il mio desiderio di lavorare su una tale mostruosità fino al completamento è minimo nella migliore delle ipotesi :-)

Riuscirà a portare a termine il lavoro? Sì. È carino? Direi che è stato un sonoro "NO!" ma, dati i tuoi vincoli, potrebbe essere il massimo che puoi sperare.

Come prova di concetto, ecco uno script SQL in DB2 (nessuna caratteristica speciale, tuttavia, dovrebbe funzionare correttamente in qualsiasi DBMS che ha una 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 questo genera le seguenti righe:

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

Scomponendo le linee di output, otteniamo:

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

che dovrebbe darti le righe originali, anche se in modo indiretto.

E questo è lo sforzo che posso mettere in qualsiasi domanda senza che il mio cervello si arrabbi, quindi ti dirò addio a meno che non mi vengano segnalati errori gravi.

Buona fortuna per il tuo progetto e tanti auguri.