Estoy tratando de crear un clob a partir de una cadena de> 4000 caracteres (suministrados en la variable de enlace file_data) para usar en un predicado de Oracle SELECT a continuación:
myQuery=
select *
from dcr_mols
WHERE flexmatch(ctab,:file_data,'MATCH=ALL')=1;
Si agrego TO_CLOB () round file_data, falla el infame límite de Oracle 4k para un varchar (está bien para <4k cadenas). El error (en SQL Developer) es:
ORA-01460: unimplemented or unreasonable conversion requested
01460. 00000 - "unimplemented or unreasonable conversion requested"
FYI La función flexmatch se usa para buscar moléculas, y se describe aquí: http://help.accelrysonline.com/ulm/onelab/1.0/content/ulm_pdfs/direct/developers/direct_2016_developersguide.pdf
La función en sí es un poco complicada, pero la esencia es que el segundo parámetro tiene que ser un clob. Entonces, mi pregunta es cómo convierto una variable de enlace Java String de más de 4000 caracteres en un clob en sql (o Java).
Probé el siguiente método (que funciona al insertar clobs) en Java (Spring boot 2) usando:
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", fileDataStr,Types.CLOB);
jdbcNamedParameterTemplate.query(myQuery,parameters,…
Este método debería funcionar, pero falla con un error de coincidencia flexible que FYI es:
SQL state [99999]; error code [29902]; ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100:
MDL-0203: Unable to read from CLOB (csfrm=1, csid=873):
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976:
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n; nested exception is java.sql.SQLException:
ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100: MDL-0203: Unable to read from CLOB (csfrm=1, csid=873):
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976:
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n"
Tenga en cuenta que estoy usando SpringBoot 2 pero no puedo obtener ningún método que use OracleConnection (obtenido de mi objeto Spring NamedParametersJdbcTemplate) para trabajar (incluso en clobs <4k), por lo que sospecho que he hecho algo estúpido. He intentado:
@Autowired
NamedParameterJdbcTemplate jdbcNamedParameterTemplate;
OracleConnection conn = this.jdbcNamedParameterTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);
Clob myClob = conn.createClob();
myClob.setString( 1, fileDataStr);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", myClob,Types.CLOB);
application.properties:
spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}/${ORA_SID}
spring.datasource.username=${ORA_USER}
spring.datasource.password=${ORA_PASS}
Tenga en cuenta que funciona bien si voy a la vieja escuela y uso una conexión que no sea de resorte más un PreparedStatement, que tiene un método setClob ():
OracleDataSource ods = new OracleDataSource();
String url ="jdbc:oracle:thin:@//" + ORA_HOST +":"+ORA_PORT +"/"+ORA_SID;
ods.setURL(url);
ods.setUser(user);
ods.setPassword(passwd);
Connection conn = ods.getConnection();
Clob myClob=conn.createClob();
PreparedStatement ps = conn.prepareStatement("select dcr_number from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1");
myClob.setString(1,myMol);
ps.setClob(1,myClob);
ResultSet rs =ps.executeQuery();
Pero preferiría una solución Spring 2 en Java o SQL. Cualquier ayuda, sugerencias apreciadas.
flexmatch()
función? Me gustaría ver la necesidad de esto. Honestamente, nunca usé valores grandes como parámetros en laWHERE
cláusula. Los he usadoINSERT
y los he recuperado usandoSELECT
. Tu caso es diferente.Respuestas:
Transmitirlo. No puede simplemente pegar un gran valor en una declaración SQL.
Necesitarás:
INSERT
instrucción (usando EMPTY_BLOB ()? ... no lo recuerdo).Esta es la forma estándar de tratar con datos masivos en Oracle. Un montón de ejemplos por ahí.
La recuperación de datos masivos (
BLOB
yCLOB
tipos) funciona de la misma manera. Simplemente use InputStreams en ese caso.fuente
Al leer la documentación de la API "BIOVIA Direct", hay un ejemplo interesante en la página 27, extracto que se muestra a continuación:
Utiliza un CLOB ya cargado . Por lo tanto, supongo que una solución lo suficientemente decente sería cargar el CLOB en una tabla suya (o precargarlos todos por adelantado), y luego simplemente usarlos.
Paso # 1 - Cargue su CLOB en una tabla:
Y use su código Java para realizar la inserción de CLOB (probablemente usando secuencias) como se muestra en otra respuesta (muchos ejemplos en Internet). Por ejemplo, inserte su contenido de datos mol con ID =
123
.Paso # 2 - Ejecute su consulta, utilizando el archivo mol ya cargado:
Puede configurar el
:id
parámetro para123
usar el archivo que cargó antes (o cualquier otro).fuente
Puedes llamar a tu antigua función de esta manera. crear una clase para manejar el conjunto de resultados
y llame a su consulta usando JdbcTemplate en su método
fuente
Tuve que volver a usar un PreparedStatement, pero mejoré un poco la implementación normal al obtener la conexión de Spring y usar apache commons BeanListHandler para asignar el ResultSet a una Lista de objetos
fuente
Puede declarar fileDataStr como CLOB usando con que es la conexión
y luego úsalo como a continuación
Además, si está utilizando SID en lugar del nombre del servicio en su cadena de conexión, intente cambiar su archivo de propiedades como se muestra a continuación
fuente