2012-05-23 49 views
59

Estoy tratando de insertar CLOB s en una base de datos (consulte related question). No puedo entender lo que está mal. Tengo una lista de aproximadamente 85 clobos que quiero insertar en una tabla. Incluso cuando inserto solo la primera clob obtengo ORA-00911: invalid character. No puedo encontrar la forma de extraer la declaración del PreparedStatement antes de que se ejecute, por lo que no puedo estar 100% seguro de que sea correcto, pero si lo hice bien, debería verse exactamente así:Dónde está mi carácter no válido (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; 

En última instancia, esta declaración insert all tendría un montón de into, por lo que simplemente no hago una declaración insert regular. No veo un personaje inválido allí, ¿verdad? (Ah, y el código anterior funciona bien cuando lo ejecuto en mi herramienta de desarrollador sql.) Y si elimino el punto y coma en el PreparedStatement, arroja un error ORA-00933: SQL command not properly ended.

En cualquier caso, aquí está mi código para ejecutar la consulta (y los valores de las variables para el ejemplo anterior).

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

¿Hay algo que me esté perdiendo a lo grande?

+0

¿Puedes ver PreparedStatement como una cadena para ver lo que contiene? –

+0

Mencioné eso en la publicación. No puedo entender cómo hacer eso. Todo lo que veo en Internet es que es bastante complicado por alguna razón ... – kentcdodds

+0

Algunos controladores JDBC permiten que toString() muestre la consulta de un PreparedStatement y otros no. No estoy seguro acerca de Oracle. –

Respuesta

146

Si utiliza literalmente la cadena exactamente como nos ha mostrado, el problema es el carácter ; al final. No puede incluir eso en la cadena de consulta en las llamadas JDBC.

Como está insertando solo una fila, un INSERT normal debería estar bien incluso cuando inserte varias filas. Usar una declaración por lotes es probable que sea más eficiente. No es necesario para INSERT ALL. Además, no necesitas el clob temporal y todo eso. Se puede simplificar el método para algo como esto (suponiendo que tengo los parámetros de la derecha):

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í, alguien más lo mencionó también. Cuando lo saco obtengo un error 'ORA-00933: el comando SQL no finalizó correctamente' ... – kentcdodds

+0

@kentcdodds: ¿por qué estás usando' insert all' en primer lugar? Un inserto normal debería estar bien. –

+0

En mi pregunta original menciono que lo que ves allí es solo una prueba para asegurarte de que solo se ejecuta una inserción. En toda realidad, habrá cerca de 85 insertos en esta declaración. – kentcdodds

6

de la parte superior de la cabeza, puede intentar utilizar el operador 'q' para la cadena literal

algo así como

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; 

Tenga en cuenta que las comillas simples de su predicado no se escapó, y la cadena se encuentra entre q '[...]'.

+0

Impresionante, me olvidé de 'q '[]''. ¡Gracias por el consejo! – kentcdodds

Cuestiones relacionadas