找到字符串,在从Java调用的Oracle函数中应为数字
编辑 把这个放在这里,以防它对其他人有帮助。我的问题是未能理解PreparedStatement是如何工作的。我相信“?”…setInt()语法是一个简单的替换,它构造一个SQL语句,解释它并将其发送到DB,但事实并非如此。下面的答案详细解释了这个问题 原始问题 我在Java应用程序中执行Oracle包函数调用时遇到一些问题。我收到以下错误:找到字符串,在从Java调用的Oracle函数中应为数字,java,oracle,function,package,Java,Oracle,Function,Package,编辑 把这个放在这里,以防它对其他人有帮助。我的问题是未能理解PreparedStatement是如何工作的。我相信“?”…setInt()语法是一个简单的替换,它构造一个SQL语句,解释它并将其发送到DB,但事实并非如此。下面的答案详细解释了这个问题 原始问题 我在Java应用程序中执行Oracle包函数调用时遇到一些问题。我收到以下错误: ORA-01858: a non-numeric character was found where a numeric was expected 我相
ORA-01858: a non-numeric character was found where a numeric was expected
我相信我已经正确构造了调用,并且我使用字符串的唯一位置是日期字段(不是数字字段)。该函数具有以下签名:
function f_get_mr_target(a_plan_id number,a_machine number,a_shift_id number,a_shift_dt date) return number;
我调用函数的java代码如下所示:
public Double checkMRTarget(int planId, int machineNum, int shiftId, String date)
{
//Instantiate the return value
Double mrTarget = null;
//Get the MR target
try
{
//Ready the connection
con = nativeDataSource.getConnection();
//The query string
String sql = "select pkg_bcs.f_get_mr_target(?,?,?,?) target from dual";
//Prepare the query
stmt = null;
stmt = con.prepareStatement(sql);
stmt.setInt(1, planId);
stmt.setInt(2, machineNum);
stmt.setInt(3, shiftId);
stmt.setString(4, date);
//Execute the query
ResultSet rs = stmt.executeQuery();
//Extract the value from the result set
mrTarget = rs.getDouble("target");
}
catch (Throwable e)
{
System.out.println("Error getting mrTarget: " + e);
}
finally
{ closeDBConnections(); }
//Return the value
return mrTarget;
}
planId = 986548
machineNum = 5227
shiftId = 10
date = "trunc(sysdate)"
Con是类中所有其他方法共享的公共连接对象。Stmt是一个PreparedStatement对象,也是共享的。参数传递如下:
public Double checkMRTarget(int planId, int machineNum, int shiftId, String date)
{
//Instantiate the return value
Double mrTarget = null;
//Get the MR target
try
{
//Ready the connection
con = nativeDataSource.getConnection();
//The query string
String sql = "select pkg_bcs.f_get_mr_target(?,?,?,?) target from dual";
//Prepare the query
stmt = null;
stmt = con.prepareStatement(sql);
stmt.setInt(1, planId);
stmt.setInt(2, machineNum);
stmt.setInt(3, shiftId);
stmt.setString(4, date);
//Execute the query
ResultSet rs = stmt.executeQuery();
//Extract the value from the result set
mrTarget = rs.getDouble("target");
}
catch (Throwable e)
{
System.out.println("Error getting mrTarget: " + e);
}
finally
{ closeDBConnections(); }
//Return the value
return mrTarget;
}
planId = 986548
machineNum = 5227
shiftId = 10
date = "trunc(sysdate)"
我已经证实了这一点
select pkg_bcs.f_get_mr_target(986548, 5227, 10, trunc(sysdate)) target from dual;
在SQLDeveloper中工作得很好。据我所知,它得到了一个数字,它期望一个数字第四个参数是date,不能与字符串一起工作。它等待一个日期对象 这是您的方法签名,传递日期对象而不是字符串
public Double checkMRTarget(int planId, int machineNum, int shiftId, Date date)
您调用了
setString
,因此Java发送了一个Oracle无法隐式转换为日期的字符串
您可以将其转换为java.sql.Date
、java.sql.Time
或java.sql.Timestamp
,方法是首先用a解析日期,并创建适当的对象,然后调用setDate
、setTime
或setTimestamp
,而不是setString
或者,您可以通过调用JDBC SQL让Oracle对其进行转换:
// Your date format may vary.
String sql = "select pkg_bcs.f_get_mr_target(?,?,?,to_date(?, 'YYYY-MM-DD')) target from dual";
将字符串数据类型替换为日期参数是一场灾难。在这种情况下(在您的代码上下文中),它肯定会出现ORA-01858
异常
参数替换需要精确绑定,这是为了实现强类型的目的。
请将第四个参数,即字符串
参数转换为日期对象
&然后实现你想要的。那就行了
此外,SQL查询中的trunc(sysdate)
不会向SQL客户端返回字符串。而是返回日期(内部转换)。这是为了使解析器能够高效且一致地识别日期类型而设计的。您为什么认为可以将字符串trunc(sysdate)
传递给需要日期类型的参数?参数替换是强类型的,您不能只为Date
参数传递任意SQL文本。这显然是对PreparedStatement工作原理的误解。谢谢你有条理地解释了这个问题!