Je voudrais exécuter le PL/SQL anonyme et j'ai besoin d'obtenir l'objet de l'ensemble de résultats. J'ai obtenu le code qui peut être fait en utilisant des curseurs à l'intérieur du bloc PL/SQL.
Mais le bloc PL/SQL lui-même proviendra de la base de données sous forme de texte. Je ne peux donc pas modifier ce bloc PL/SQL. Et il ne renverra que deux valeurs dont les noms de colonnes seront toujours les mêmes. Il renverra la liste des valeurs de combinaison de 2 colonnes.
Ici, je donne un exemple PL/SQL.
BEGIN
RETURN 'select distinct fundname d, fundname r from <table> where condition order by 1';
EXCEPTION
WHEN OTHERS THEN
RETURN 'SELECT ''Not Available'' d, ''Not Available'' r FROM dual';
END;
Toute réponse sera si utile.
Voici un exemple autonome de la façon "d'exécuter le PL/SQL anonyme et d'obtenir l'objet d'ensemble de résultats"
import Java.sql.CallableStatement;
import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.ResultSet;
import Java.sql.Types;
import Oracle.jdbc.OracleTypes;
public class CallPLSQLBlockWithOneInputStringAndOneOutputStringParameterAndOneOutputCursorParameter {
public static void main(String[] args) throws Exception {
DriverManager.registerDriver(new Oracle.jdbc.OracleDriver());
// Warning: this is a simple example program : In a long running application,
// error handlers MUST clean up connections statements and result sets.
final Connection c = DriverManager.getConnection("jdbc:Oracle:thin:@localhost:1521:XE", "system", "manager");
String plsql = "" +
" declare " +
" p_id varchar2(20) := null; " +
" l_rc sys_refcursor;" +
" begin " +
" p_id := ?; " +
" ? := 'input parameter was = ' || p_id;" +
" open l_rc for " +
" select 1 id, 'hello' name from dual " +
" union " +
" select 2, 'peter' from dual; " +
" ? := l_rc;" +
" end;";
CallableStatement cs = c.prepareCall(plsql);
cs.setString(1, "12345");
cs.registerOutParameter(2, Types.VARCHAR);
cs.registerOutParameter(3, OracleTypes.CURSOR);
cs.execute();
System.out.println("Result = " + cs.getObject(2));
ResultSet cursorResultSet = (ResultSet) cs.getObject(3);
while (cursorResultSet.next ())
{
System.out.println (cursorResultSet.getInt(1) + " " + cursorResultSet.getString(2));
}
cs.close();
c.close();
}
}
L'exemple de requête ci-dessus "sélectionnez 1 id, nom" bonjour "de la double union sélectionnez 2," peter "de la double;" peut être remplacé par n'importe quelle requête.
Essayez quelque chose comme ça (pseudo-code):
[create or replace] function get_dataset (p_query in varchar2) return sys_refcursor
as
l_returnvalue sys_refcursor;
begin
open l_returnvalue for p_query;
return l_returnvalue;
end get_dataset;
Le REF CURSOR qui est retourné peut être traité comme un jeu de données normal.
Et méfiez-vous de l'injection SQL lorsque vous utilisez une approche comme celle-ci ...
Tout d'abord, le code que vous avez publié n'est pas valide. Un bloc PL/SQL anonyme ne peut pas renvoyer une expression. Et aucun bloc PL/SQL ne peut retourner le résultat d'une requête comme ça. Vous devez faire quelque chose comme déclarer un REF CURSOR et ouvrir ce curseur à l'aide des différentes instructions SQL.
Puisqu'un bloc PL/SQL anonyme ne peut rien renvoyer à un appelant, l'architecture que vous décrivez est problématique. Au minimum, vous devez modifier le bloc anonyme afin qu'il y ait une variable de liaison que votre code JDBC puisse enregistrer. Quelque chose comme (adapté d'un exemple dans Menon's Expert Oracle JDBC Programming (notez que j'ai peut-être introduit quelques erreurs de syntaxe mineures)
CallableStatement stmt := null;
ResultSet rset := null;
String query := 'DECLARE
FUNCTION get_result
RETURN SYS_REFCURSOR
AS
l_rc SYS_REFCURSOR;
BEGIN
OPEN l_rc
FOR SELECT DISTINCT fundname d, fundname r
FROM some_table
WHERE some_condition
ORDER BY 1;
RETURN l_rc;
EXCEPTION
WHEN others THEN
OPEN l_rc
FOR SELECT 'Not Available' d, 'Not Available' r
FROM dual;
RETURN l_rc;
END get_result;
BEGIN
? := get_result;
END;';
try {
cstmt := conn.prepareCall( query );
cstmt.registerOutParameter( 1, OracleTypes.CURSOR );
cstmt.execute();
rset := (ResultSet) cstmt.getObject( 1 );
}
finally {
<<close cstmt & rset>>
}