web-dev-qa-db-fra.com

Où est mon personnage invalide (ORA-00911)

J'essaie d'insérer CLOBs dans une base de données (voir question connexe ). Je n'arrive pas à comprendre ce qui ne va pas. J'ai une liste d'environ 85 points que je veux insérer dans un tableau. Même en insérant seulement le premier clob, je reçois ORA-00911: invalid character. Je n'arrive pas à comprendre comment extraire la déclaration du PreparedStatement avant qu'elle ne soit exécutée. Je ne peux donc pas être sûr à 100% que c'est vrai, mais si j'ai bien compris, elle devrait alors ressembler exactement à cette:

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 fin de compte, ceci insert all déclaration aurait beaucoup de into, raison pour laquelle je ne fais pas une déclaration normale insert. Je ne vois pas de personnage invalide dedans, n'est-ce pas? (Oh, et le code ci-dessus fonctionne correctement lorsque je l'exécute dans mon outil de développement SQL .) Et si je supprime le point-virgule dans le PreparedStatement, il jette un ORA-00933: SQL command not properly ended Erreur.

Dans tous les cas, voici mon code pour exécuter la requête (et les valeurs des variables pour l'exemple ci-dessus).

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

Y a-t-il quelque chose qui me manque grand temps?

64
kentcdodds

Si vous utilisez le littéral chaîne exactement comme vous nous l'avez montré, le problème est le ; caractère à la fin. Vous ne pouvez pas inclure cela dans la chaîne de requête dans les appels JDBC.

Comme vous n'insérez qu'une seule ligne, un INSERT normal devrait suffire, même lors de l'insertion de plusieurs lignes. L'utilisation d'une déclaration par lot est probablement plus efficace. Pas besoin d INSERT ALL. De plus, vous n'avez pas besoin du clob temporaire et de tout ça. Vous pouvez simplifier votre méthode à quelque chose comme ceci (en supposant que les paramètres soient corrects):

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();
156

Pouvez-vous essayer d'utiliser l'opérateur 'q' pour le littéral chaîne?

quelque chose comme

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;

Notez que les guillemets simples de votre prédicat ne sont pas échappés et que la chaîne se situe entre q '[...]'.

6
user507484