2009-10-05 7 views
0

Je travaille avec une instruction Java préparée qui extrait des données d'une base de données Oracle. En raison de certains problèmes de performances, la requête utilise une "colonne virtuelle" comme index.Instruction préparée - utilisation d'une fonction dans le cadre de la clause where

La requête ressemble à ceci:

String status = "processed"; 
String customerId = 123; 
String query = "SELECT DISTINCT trans_id FROM trans WHERE status = " + status + " AND FN_GET_CUST_ID(trans.trans_id) = " + customerId; 

Connection conn = getConnection(); 
PreparedStatement ps = null; 
ResultSet rs = null; 

try { 
    ps = conn.prepareStatement(query); 
    ps.execute(); 
    ... 
} catch (...) 

Cela ne fonctionne pas. Avoir la fonction dans le cadre de la clause where provoque une exception SQLException. Je connais CallableStatement et je sais que je pourrais l'utiliser d'abord, puis concaténer les résultats. Cependant, cette table utilise FN_GET_CUST_ID (trans_id) comme partie de son index. Existe-t-il un moyen d'utiliser une instruction préparée avec une fonction de base de données en tant que paramètre de requête?

+1

Le statut traité doit être indiqué. Peut-être que c'est ce qui provoque votre exception, non? – quosoo

+0

Avoir une fonction dans la clause WHERE devrait fonctionner, votre problème se situe probablement ailleurs. Pourriez-vous publier le code d'erreur et le message (SQLException.getErrorCode)? La requête fonctionne-t-elle réellement dans SQL * Plus? –

+0

Désolé, l'exemple que j'ai posté n'a pas été copié textuellement. J'ai essayé de le réduire pour enlever beaucoup de choses excédentaires non essentielles. Les citations manquantes ne sont pas le problème. – emulcahy

Répondre

6
  1. Ne jamais concaténer les arguments pour le SQL dans la chaîne. Utilisez toujours des espaces réservés (?) et setXxx(column, value);.

  2. Vous obtiendrez la même erreur si vous exécutez le SQL dans votre outil de base de données préféré. Le problème est que Oracle ne peut pas utiliser la fonction pour une raison quelconque. Quel code d'erreur obtenez-vous?

+2

+1 pour les espaces réservés – Powerlord

+1

Le problème était que la fonction n'avait pas de privilèges d'exécution publics. # 2 dans le commentaire d'Aaron "Le problème est que Oracle ne peut pas utiliser la fonction pour une raison quelconque." C'est ce qui m'a finalement conduit à trouver le problème, lui donnant ainsi du crédit. – emulcahy

0

À première vue, la requête semble être incorrecte. Il vous manque une apostrophe avant et après l'utilisation de la variable status (en supposant que l'état est une colonne varchar).

String query = "SELECT DISTINCT trans_id FROM trans 
WHERE status = '" + status + "' AND FN_GET_CUST_ID(trans.trans_id) = " + customerId; 

EDIT: Je ne suis pas d'origine java. Cependant, comme l'a dit @Aron, il est préférable d'utiliser des espaces réservés & puis d'utiliser une méthode pour définir les valeurs des paramètres à éviter SQL Injection.

+0

C'est exact comme je l'ai souligné dans mon premier commentaire à la question. Cependant, il est probablement préférable d'utiliser les espaces réservés dans les requêtes qu'Aaron a mentionnées, sinon il n'y a aucun avantage à utiliser l'instruction PreparedStatement. – quosoo

1

Si l'ID client est numérique, laissez int int pas String. Ensuite, essayez de faire ce qui suit:

String query = "SELECT DISTINCT trans_id FROM trans WHERE status = ? AND FN_GET_CUST_ID(trans.trans_id) = ?"; 

ps = conn.prepareStatement(query); 
ps.setString(1, status); 
ps.setInt(2, customerId); 
ps.execute(); 

Outre d'autres avantages de la déclaration préparée vous ne devez retenir sur les citations de chaîne (ce qui provoque votre erreur le plus probable) et échapper à des caractères spéciaux.

Questions connexes