如何使用 ODP.NET 在存储过程中 return 来自 Oracle 动态 SQL 的记录

How to return records from Oracle dynamic SQL in a stored procedure with ODP.NET

我正在尝试弄清楚如何获取存储过程中保存的动态 sql 查询的结果。

存储过程很简单:

CREATE OR REPLACE PROCEDURE PORT_CALL_PROCEDEURE(queryin IN varchar2,result out varchar2)
is

BEGIN

   dbms_output.put_line(queryin);
   EXECUTE IMMEDIATE queryin;    
END ;

我从 VS 调用它的方式是:

OracleCommand oracmd = GetCommand("PORT_CALL_PROCEDEURE", oraconn);
oraconn.Open();
string row = string.Empty;
StringBuilder sb = new StringBuilder();
sb.Append("SELECT * into result Where port = 'MSO'and Map = 'Local'");
sb.Append(" FROM VESSEL");
string commandString = sb.ToString();
command.Parameters.Add("query_in", OracleDbType.Varchar2, 10000000,      commandString, ParameterDirection.Input);
command.Parameters.Add("result", OracleDbType.Varchar2, 10000000,     `commandString, ParameterDirection.Output);`
oracmd.ExecuteNonQuery();

我遇到异常:

{"ORA-00905: missing keyword
  ORA-06512: at \"BOAZ.PORT_CALL_PROCEDEURE\", line 7
  ORA-06512: at line 1"}

有什么帮助吗? 谢谢。

错误说 EXECUTE IMMEDIATE 没听懂 result

修改execute immediate喜欢

execute immediate queryin into result.

一样发送查询
select clmn  from tbl where ....

演示:

declare
v_name varchar2(50);
begin
execute immediate q'{select 'my name' into v_name from dual}';
dbms_output.put_line(v_name);
end;
/
ORA-00905: missing keyword
ORA-06512: at line 4
00905. 00000 -  "missing keyword"


declare
v_name nvarchar2(50);
begin
execute immediate q'{select 'my name' from dual}' into v_name;
dbms_output.put_line(v_name);
end;
/
anonymous block completed
my name

这个解决方案对我有用:

Oracle 程序代码:

CREATE OR REPLACE PROCEDURE PORT_CALL_PROCEDEURE
  (queryin IN varchar2, result out varchar2) is
BEGIN
   dbms_output.put_line(queryin);
   EXECUTE IMMEDIATE queryin into result;
END ;

C#代码:

OracleCommand oracmd = new OracleCommand("PORT_CALL_PROCEDEURE", oraconn);
oracmd.CommandType = CommandType.StoredProcedure;
oracmd.Parameters.Add("query_in", OracleDbType.Varchar2, 10000000, 
    "select * from dual where dummy='X'", ParameterDirection.Input);
oracmd.Parameters.Add("result", OracleDbType.Varchar2, 10000000, 
    null, ParameterDirection.Output);
oracmd.ExecuteNonQuery();
Console.WriteLine(oracmd.Parameters["result"].Value);

这适用于标量、varchar 值。要获得 DataTable 的结果,您需要将 Oracle 过程中的类型更改为 sys_refcursor,将 C# 中的类型更改为 RefCursor(未测试)。

要执行该查询,您不需要动态 SQL 也不需要 PL/SQL 存储过程。如果你想学习这两件事没有什么不好,但试着只做一件事你一次不知道。这将有助于您识别错误。

您在代码中犯了三个主要错误:

  1. 在您的查询中,WHERE 子句位于 FROM
  2. 之前
  3. SELECT INTO 仅在 PL/SQL 块中有效,立即执行不会执行
  4. DBMS_OUTPUT 如果您不调用 DBMS_OUTPUT.GET_LINES 并且在它工作之前没有做所有需要做的事情,那么 DBMS_OUTPUT 将无法在 .NET 中工作

所以这是您需要以简单正确的方式执行它的 C# 代码:

OracleConnection connection = new OracleConnection();
connection.ConnectionString = "xxxYYYzzz";
connection.Open();

OracleCommand oracmd = connection.CreateCommand();
oraCmd.CommandText = 
@"SELECT * 
FROM VESSEL
Where port = 'MSO'and Map = 'Local'".Replace("\r", ""); // Oracle SQL Parset doesn't like '\r' char
object res = oraCmd.ExecuteScalar();

Console.WriteLine(res);