J'essaie de créer un clob à partir d'une chaîne de> 4000 caractères (fourni dans la variable de liaison file_data) à utiliser dans un prédicat Oracle SELECT ci-dessous:
myQuery=
select *
from dcr_mols
WHERE flexmatch(ctab,:file_data,'MATCH=ALL')=1;
Si j'ajoute TO_CLOB () autour de file_data, il échoue à la fameuse limite Oracle 4k pour un varchar (c'est bien pour <4k strings). L'erreur (dans SQL Developer) est:
ORA-01460: unimplemented or unreasonable conversion requested
01460. 00000 - "unimplemented or unreasonable conversion requested"
Pour info La fonction flexmatch est utilisée pour rechercher des molécules et est décrite ici: http://help.accelrysonline.com/ulm/onelab/1.0/content/ulm_pdfs/direct/developers/direct_2016_developersguide.pdf
La fonction elle-même est un peu compliquée mais l'essentiel est que le 2ème paramètre doit être un clob. Donc, ma question est de savoir comment convertir une chaîne Java bind_variable de plus de 4000 caractères en un clob en sql (ou Java).
J'ai essayé la méthode ci-dessous (qui fonctionne lors de l'insertion de clobs) en Java (Spring boot 2) en utilisant:
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", fileDataStr,Types.CLOB);
jdbcNamedParameterTemplate.query(myQuery,parameters,…
Cette méthode devrait fonctionner, mais elle échoue avec une erreur de flexmatch convergée dont FYI est:
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"
Notez que j'utilise SpringBoot 2 mais je ne peux obtenir aucune méthode utilisant un OracleConnection (obtenu à partir de mon objet Spring NamedParametersJdbcTemplate) pour travailler (même sur des clobs <4k), donc je soupçonne que j'ai fait quelque chose de stupide. J'ai essayé:
@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}
Notez que cela fonctionne bien si je vais à l'ancienne et que j'utilise une connexion sans ressort plus un PreparedStatement, qui a une méthode 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();
Mais je préférerais une solution Spring 2 en Java ou Sql. Toute aide, suggestions appréciées.
flexmatch()
fonction? J'aimerais voir la nécessité de cela. Honnêtement, je n'ai jamais utilisé de grandes valeurs comme paramètres dans laWHERE
clause. Je les ai utilisésINSERT
et je les ai récupérés en utilisantSELECT
. Votre cas est différent.Réponses:
Diffusez-le. Vous ne pouvez pas simplement coller une énorme valeur dans une instruction SQL.
Vous devrez:
INSERT
instruction (en utilisant EMPTY_BLOB ()? ... je ne me souviens pas très bien).Il s'agit de la manière standard de traiter des données massives dans Oracle. Beaucoup d'exemples là-bas.
La récupération de données massives (
BLOB
et deCLOB
types) fonctionne de la même manière. Utilisez simplement InputStreams dans ce cas.la source
En lisant la documentation de l'API "BIOVIA Direct", voici un exemple intéressant à la page 27, extrait ci-dessous:
Il utilise un CLOB déjà chargé . Par conséquent, je suppose qu'une solution décente serait de charger le CLOB dans une de vos tables (ou de les précharger tous à l'avance), puis de les utiliser.
Étape # 1 - Chargez votre CLOB dans une table:
Et utilisez votre code Java pour effectuer l'insertion CLOB (probablement à l'aide de flux) comme indiqué dans une autre réponse (de nombreux exemples sur Internet). Par exemple, insérez votre contenu de données mol avec ID =
123
.Étape # 2 - Exécutez votre requête, en utilisant le fichier mol déjà chargé:
Vous pouvez définir le
:id
paramètre pour123
utiliser le fichier que vous avez chargé avant (ou tout autre).la source
Vous pouvez appeler votre ancienne fonction comme ça. créer une classe pour gérer le ResultSet
et appelez votre requête en utilisant le JdbcTemplate dans votre méthode
la source
J'ai dû revenir à l'utilisation d'un PreparedStatement, mais j'ai un peu amélioré l'implémentation normale en obtenant la connexion de Spring et en utilisant apache commons BeanListHandler pour mapper le ResultSet à une liste d'objets
la source
Vous pouvez déclarer fileDataStr comme CLOB en utilisant con qui est la connexion
puis l'utiliser comme ci-dessous
Aussi, si vous utilisez SID au lieu du nom du service dans votre chaîne de connexion, essayez de changer votre fichier de propriétés comme ci-dessous
la source