2010-04-29 9 views
5

Devo esportare una tabella Oracle come INSERT STATEMENTS.ESPORTAZIONE COME INSERIRE DICHIARA: Ma in SQL Plus la linea ha la precedenza su 2500 caratteri!

Ma gli INSERT STATEMENT così generati, sostituiscono 2500 caratteri.

Sono obbligato ad eseguirli in SQL Plus, quindi ricevo un messaggio di errore.

Questa è la mia tabella di Oracle:

CREATE TABLE SAMPLE_TABLE 
(
    C01 VARCHAR2 (5 BYTE) NOT NULL, 
    C02 NUMBER (10) NOT NULL, 
    C03 NUMBER (5) NOT NULL, 
    C04 NUMBER (5) NOT NULL, 
    C05 VARCHAR2 (20 BYTE) NOT NULL, 
    c06 VARCHAR2 (200 BYTE) NOT NULL, 
    c07 VARCHAR2 (200 BYTE) NOT NULL, 
    c08 NUMBER (5) NOT NULL, 
    c09 NUMBER (10) NOT NULL, 
    c10 VARCHAR2 (80 BYTE), 
    c11 VARCHAR2 (200 BYTE), 
    c12 VARCHAR2 (200 BYTE), 
    c13 VARCHAR2 (4000 BYTE), 
    c14 VARCHAR2 (1 BYTE) DEFAULT 'N' NOT NULL, 
    c15 CHAR (1 BYTE), 
    c16 CHAR (1 BYTE) 
); 

ipotesi:

a) sono costretto a esportare i dati della tabella come istruzioni INSERT; Sono autorizzato a utilizzare le istruzioni UPDATE, per evitare l'errore SQL * Plus "l'input sp2-0027 è troppo lungo (> 2499 caratteri)";

b) Sono OBBLIGATO utilizzare SQL * Plus per eseguire lo script così generato.

c) Si supponga che ogni record possa contenere caratteri speciali: CHR (10), CHR (13) e così via;

d) NON POSSO utilizzare SQL Loader;

e) NON POSSO esportare e quindi importare la tabella: Posso solo aggiungere il "delta" utilizzando le istruzioni INSERT/UPDATE tramite SQL Plus.

+1

Un punto non è chiaro e questo è importante. Avete inserimenti/aggiornamenti in cui il * valore * di c13 supera i 2499 caratteri? Oppure, hai semplicemente delle istruzioni in cui la lunghezza dell'istruzione * supera i 2499 caratteri? (Il primo è difficile, il secondo è facile da risolvere) –

+0

La risposta è la seguente: Nella mia tabella Oracle denominata SAMPLE_TABLE, ho 80 record in cui la lunghezza del campo C13, di tipo VARCHAR2 (4000), è 3762 personaggi. Ciò significa che, naturalmente, il VALORE di C13 supera i 2499 caratteri. In questo caso, possiamo osservare che la lunghezza della DICHIARAZIONE supera anche 2499 caratteri. – UltraCommit

+0

@Il pollo in cucina - Qual è la chiave principale del tavolo di destinazione? – Thomas

risposta

5

Wow, questi limiti sono piuttosto limitanti, ma penso che potrebbe esserci un modo per aggirarlo. Penso che potresti dover scrivere il tuo piccolo script per questo.

Vorrei usare Java con JDBC da solo (ma qualsiasi linguaggio che possa connettersi e leggere il database e le stringhe di output, lo farà), scrivendo un piccolo programma che recuperava un set di record di ogni riga nel database. Quindi, per ognuna di queste righe:

  • Costruire una dichiarazione di inserimento con i dati completi. Se questo è inferiore a 2000 byte, devi solo inviarlo al file e passare alla riga successiva.

  • In caso contrario, creare un'istruzione di inserimento per ogni campo, ma lasciare il campo c13 come '' (vuoto).

  • Quindi, fino a quando la stringa c13input è maggiore di 2000 caratteri, uscita un'istruzione di aggiornamento della forma "update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..." (aggiungendo i prossimi 2000 caratteri) e poi fare c13input = c13input.substring(2000) per togliere quei personaggi dalla stringa.

  • Una volta che c13input è inferiore o uguale a 2000 caratteri di lunghezza, è sufficiente emettere un aggiornamento finale per collegarlo alla fine.

Questo permette di mantenere i istruzioni SQL individuali intorno al marchio di 2000 caratteri ed efficiente esegue lo SQL corretto per ripopolare un'altra tabella del database.

Questo è il tipo di cosa sto parlando (per una tabella che contiene solo una chiave primaria c1 e un grande honkin' 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 morph le stringhe per consentire inserimenti di caratteri speciali - Non sono sicuro del formato che Oracle si aspetta da questi, ma si spera che sia una semplice questione di passare le stringhe (r.get("c13") se la lunghezza dell'inserto completo è inferiore a 2000, f.substring(0,2000) e f se si stiamo costruendo anche gli aggiornamenti) ad una funzione di aiuto per farlo.

Se è probabile che tale morphing aumenti la dimensione della linea stampata, è possibile che si desideri riportare la soglia a 1000 per essere sicuri, per garantire che la stringa trasformata non risulti in una riga superiore a PL/SQL limite.

Scusa se questo sembra complicato, ma le restrizioni che hai dichiarato ci hanno un po 'ridimensionato. Potrebbe esserci un modo migliore, ma non riesco a pensare a uno che soddisfa tutti i i tuoi criteri.


Aggiornamento: Sembra che tu sei ancora più azzoppato di quanto originariamente pensato: se si deve limitare a SQL per la generazione lo script così come eseguirlo, c'è un modo, per quanto sia tortuoso

È possibile utilizzare SQL per generare SQL. Usando il mio tavolo citato con c1 e c13, si può fare:

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

che vi darà tutta la vostra linea di base insert dichiarazioni a duplicare tutto, ma la colonna c13.

Quello che devi fare è generare più istruzioni per l'impostazione di c13. Per aggiornare c13 per tutti i valori di lunghezza 1000 o meno (insieme 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 

Poi, per update C13 per tutti i valori compresi tra 1001 e 2000 caratteri (SET 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 vanno da 2001 a 3000 e da 3001 a 4000 di lunghezza.

Probabilmente ci sarà bisogno di qualche ritocco. Sono felice di darti un modo per risolverlo, ma il mio desiderio di lavorare su una tale mostruosità fino al completamento è minimo nel migliore dei casi :-)

Avrà finito il lavoro? Sì. È carino? Direi che è stato un clamoroso "NO!" ma, dati i tuoi limiti, potrebbe essere il meglio che puoi sperare.


Come una prova di concetto, ecco uno script SQL in DB2 (senza caratteristiche particolari, però, dovrebbe funzionare bene in qualsiasi DBMS che ha un length e substr equivalenti):

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

scoppiare le linee di uscita, otteniamo:

012.351.641,061 mila
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 darvi le righe originali, anche se in modo indiretto.


E questo è tanto sforzo come posso mettere in qualsiasi domanda senza il mio friggere il cervello, quindi mi do il adieu a meno che eventuali errori gravi sono segnalati a me.

Buona fortuna per il tuo progetto e auguri.

+0

Ho scritto che ho bisogno di una soluzione PL/SQL. Non conosco Java. Inoltre, non sono autorizzato ad eseguire classi Java nell'ambiente di produzione. Posso solo selezionare/INSERIRE/AGGIORNARE in linguaggio PL/SQL. Sono autorizzato a creare un PACCHETTO JAVA, questo significa un pacchetto PL/SQL che utilizzava classi JAVA. Sei in grado di convertire il tuo script in un PACCHETTO JAVA, compilabile in ORACLE PL/SQL? – UltraCommit

+1

No.Se sei limitato a PL/SQL per la creazione dello script, in pratica ti troverai in un momento molto difficile. È un buon linguaggio per lo scripting di SQL, ma non è buono per roba generica. Hai dichiarato che eri "OBBLIGATO utilizzare SQL * Plus per eseguire lo script così generato" e non hai detto nulla sui requisiti per realizzare effettivamente lo script, motivo per cui ho suggerito il mio approccio. Oracle ti permette di connetterti tramite JDBC abbastanza facilmente e gli strumenti Java sono gratuiti, quindi è ancora la mia risposta, semplicemente perché limitarti a PL/SQL sarà molto più difficile dell'apprendimento di Java/JDBC. – paxdiablo

+1

Detto questo, ti darò un inizio (guarda la mia modifica) ma sarà una lunga e tortuosa strada da percorrere :-) – paxdiablo

0

È possibile utilizzare lo strumento di jailer (http://jailer.sf.net) per esportare i dati della tabella come INSERT STATEMENTS.

+0

Per quanto ne so, non ha problemi ad esportarli, ma l'importazione/esecuzione dello script generato sta causando problemi a causa di linee troppo lunghe. – bert

+0

Hai ragione, ma lo strumento che ho citato avvolge le linee in modo che sia possibile usare SQL * Plus per importare i dati. – RDoubleYou

+0

Confermo di non avere problemi ad esportare i record come INSERT STATEMENTS, perché uso TOAD (di Quest Software). Nel pomeriggio proverò ad usare lo strumento Jailer, per vedere cosa succede esportando i miei dati di tabella con Jailer. L'obiettivo è che gli INSERT STATEMENTS generati con Jailer non forniscano l'errore SQL * Plus "l'input sp2-0027 è troppo lungo (> 2499 caratteri)". – UltraCommit