2012-05-23 2 views
59

Sto tentando di inserire CLOB s in un database (vedere related question). Non riesco a capire cosa c'è che non va. Ho una lista di circa 85 clob che voglio inserire in una tabella. Anche inserendo solo il primo clob ottengo ORA-00911: invalid character. Non riesco a capire come ottenere la dichiarazione dal PreparedStatement prima che venga eseguita, quindi non posso essere sicuro al 100% che sia giusto, ma se ho capito bene, dovrebbe apparire esattamente così:Dov'è il mio carattere non valido (ORA-00911)

insert all 
    into domo_queries values ('select 
substr(to_char(max_data),1,4) as year, 
substr(to_char(max_data),5,6) as month, 
max_data 
from dss_fin_user.acq_dashboard_src_load_success 
where source = ''CHQ PeopleSoft FS''') 
select * from dual; 

In definitiva, questa istruzione insert all avrebbe un sacco di into 's, motivo per cui io proprio non faccio una dichiarazione regolare insert. Non vedo un personaggio non valido lì dentro, vero? (Oh, e quel codice sopra funziona correttamente quando lo eseguo nel mio strumento sql per sviluppatori.) E se rimuovo il punto e virgola nello PreparedStatement, genera un errore ORA-00933: SQL command not properly ended.

In ogni caso, ecco il mio codice per l'esecuzione della query (e i valori delle variabili per l'esempio sopra).

public ResultSet executeQuery(String connection, String query, QueryParameter... params) throws DataException, SQLException { 
    // query at this point = "insert all 
          //into domo_queries values (?) 
          //select * from dual;" 
    Connection conn = ConnectionPool.getInstance().get(connection); 
    PreparedStatement pstmt = conn.prepareStatement(query); 
    for (int i = 1; i <= params.length; i++) { 
    QueryParameter param = params[i - 1]; 
    switch (param.getType()) { //The type in the example is QueryParameter.CLOB 
     case QueryParameter.CLOB: 
     Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION); 
     clob.setString(i, "'" + param.getValue() + "'"); 
     //the value of param.getValue() at this point is: 
     /* 
     * select 
     * substr(to_char(max_data),1,4) as year, 
     * substr(to_char(max_data),5,6) as month, 
     * max_data 
     * from dss_fin_user.acq_dashboard_src_load_success 
     * where source = ''CHQ PeopleSoft FS'' 
     */ 
     pstmt.setClob(i, clob); 
     break; 
     case QueryParameter.STRING: 
     pstmt.setString(i, "'" + param.getValue() + "'"); 
     break; 
    } 
    } 
    ResultSet rs = pstmt.executeQuery(); //Obviously, this is where the error is thrown 
    conn.commit(); 
    ConnectionPool.getInstance().release(conn); 
    return rs; 
} 

C'è qualcosa che mi manca solo il grande tempo?

+0

Puoi vedere il PreparedStatement come una stringa per vedere cosa contiene? –

+0

L'ho menzionato nel post. Non riesco a capire come farlo. Tutto quello che vedo su Internet è che è piuttosto complicato per qualche motivo ... – kentcdodds

+0

Alcuni driver JDBC consentono a toString() di mostrare la query da un PreparedStatement e altri no. Non sono sicuro di Oracle. –

risposta

146

Se si utilizza la stringa letterale esattamente come ci hai mostrato, il problema è il carattere ; alla fine. Non è possibile includerlo nella stringa di query nelle chiamate JDBC.

Come si inserisce solo una riga, un normale INSERT dovrebbe essere perfetto anche quando si inseriscono più righe. L'utilizzo di una dichiarazione in batch è probabilmente più efficace in ogni caso. Non c'è bisogno di INSERT ALL. Inoltre non è necessario il clob temporaneo e tutto il resto. È possibile semplificare il metodo a qualcosa di simile (supponendo che ho ottenuto i parametri a destra):

String query1 = "select substr(to_char(max_data),1,4) as year, " + 
    "substr(to_char(max_data),5,6) as month, max_data " + 
    "from dss_fin_user.acq_dashboard_src_load_success " + 
    "where source = 'CHQ PeopleSoft FS'"; 

String query2 = "....."; 

String sql = "insert into domo_queries (clob_column) values (?)"; 
PreparedStatement pstmt = con.prepareStatement(sql); 
StringReader reader = new StringReader(query1); 
pstmt.setCharacterStream(1, reader, query1.length()); 
pstmt.addBatch(); 

reader = new StringReader(query2); 
pstmt.setCharacterStream(1, reader, query2.length()); 
pstmt.addBatch(); 

pstmt.executeBatch(); 
con.commit(); 
+0

Sì, qualcun altro ha menzionato anche questo. Quando lo prendo, ricevo un errore "ORA-00933: comando SQL non terminato correttamente" ... – kentcdodds

+0

@kentcdodds: perché stai usando 'insert all' in primo luogo? Un inserto normale dovrebbe andare bene. –

+0

Nella mia domanda iniziale, dico che quello che vedi è solo un test per assicurarsi che venga eseguito solo un inserto. In tutta l'attualità, ci saranno circa 85 inserti in questa affermazione. – kentcdodds

6

della parte superiore della mia testa, si può provare ad usare l'operatore 'q' per la stringa letterale

qualcosa come

insert all 
    into domo_queries values (q'[select 
substr(to_char(max_data),1,4) as year, 
substr(to_char(max_data),5,6) as month, 
max_data 
from dss_fin_user.acq_dashboard_src_load_success 
where source = 'CHQ PeopleSoft FS']') 
select * from dual; 

si noti che le virgolette singole del vostro predicato non siamo scampati, e la stringa si trova tra q '[...]'.

+0

Fantastico, mi sono dimenticato di 'q '[]''. Grazie per il consiglio! – kentcdodds