【问题标题】:ORA-00933: SQL command not properly ended on jdbc callORA-00933: SQL 命令未在 jdbc 调用上正确结束
【发布时间】:2016-08-25 12:34:36
【问题描述】:

我有这个问题:

SELECT col FROM table WHERE   
last_updated > SYS_EXTRACT_UTC(systimestamp) - INTERVAL ?  DAY TO SECOND(1)

在我的数据库访问代码中,

stmt.setString(1, "0 00:01:30.0");//stmt is OraclePreparedStatement
rs = stmt.executeQuery();//results in exception

异常消息:java.sql.SQLSyntaxErrorException:ORA-00933:SQL 命令未正确结束

如果我替换绑定并在 Sql Developer 中运行查询,它会正常运行。 java代码哪里错了?

【问题讨论】:

  • 在 SELECT 语句的末尾添加分号 (;) 看看是否有帮助。
  • @mathguy:不,这会让事情变得更糟:stackoverflow.com/q/10728377/330315
  • 不幸的是,您不能将间隔的值作为这样的参数传递。
  • @a_horse_with_no_name - 谢谢!的确,直到五秒钟前(在我完成打字时更多),我是许多认为 ;是 Oracle SQL 中的语句终止符。现在我知道得更清楚了。 (我只是快速查看了 SQL*Plus 手册,如果您知道 ';' 不是 SQL 的一部分,您可以看到它与手册所说的一致;但如果您事先不知道,它是从手册的编写方式很难理解。)
  • @mathguy:; SQL 中的语句终止符 - SQL 客户端使用它来识别各个语句。但在 JDBC 中,您只发送 single 语句,因此您可能不会在查询字符串中包含 ;。然而,这是 Oracle JDBC 驱动程序(或后端)的限制 - 其他驱动程序或 DBMS do 允许发送 ;

标签: java oracle jdbc


【解决方案1】:

问题在于INTERVAL '0 00:01:30.0' DAY TO SECOND(1) 是数据类型INTERVAL 的文字。所以你不能在里面使用位置参数。

您必须使用转换函数NUMTOYMINTERVALNUMTODSINTERVAL 之一。

准备好的语句的修改后的 SQL 将是

SELECT col FROM table WHERE   
last_updated > SYS_EXTRACT_UTC(systimestamp) - NUMTODSINTERVAL(?,'SECOND')

并且需要设置参数为

stmt.setInt(1, 90);

edit 正如亚历克斯自己所说的那样。另一种方式

SELECT col FROM table WHERE   
last_updated > SYS_EXTRACT_UTC(systimestamp) - TO_DSINTERVAL(?)

并且参数可以设置为字符串

stmt.setString("0 00:01:30.0");

手动检查间隔是否相同

select NUMTODSINTERVAL(90,'SECOND') as "NUMTODSINTERVAL", 
       INTERVAL '0 00:01:30.0' DAY TO SECOND(1) as "INTERVAL",
       TO_DSINTERVAL('0 00:01:30.0') as "TO_DSINTERVAL"
from dual

输出

NUMTODSINTERVAL     INTERVAL            TO_DSINTERVAL      
------------------- ------------------- -------------------
+00 00:01:30.000000 +00 00:01:30.000000 +00 00:01:30.000000

【讨论】:

  • 但是现在你必须将区间字符串转换为数字;为什么不使用to_dsinterval() 直接获取现有字符串值?
  • @AlexPoole 你可以。这取决于您的代码中如何使用间隔。我发现字符串表示不是很常见。 ;-) 我将您的示例添加到我的答案中。
【解决方案2】:

正如@a_horse_with_no_name 在评论中所说,您不能将间隔值作为参数传递。那个形式是an interval literal,你不能对文字部分使用绑定变量。

您可以将查询更改为使用the to_dsinterval() function

SELECT col FROM table WHERE   
last_updated > SYS_EXTRACT_UTC(systimestamp) - TO_DSINTERVAL(?)

使用 SQL*Plus/SQL Developer 绑定变量的快速演示:

var val varchar2(30);
exec :val := '0 00:01:30.0';

相当于您使用 CTE 提供虚拟数据的查询:

with t(last_updated, col) as (select systimestamp, 1 from dual)
SELECT col FROM t WHERE   
last_updated > SYS_EXTRACT_UTC(systimestamp) - INTERVAL :val  DAY TO SECOND(1);

SQL Error: ORA-00933: SQL command not properly ended

用函数代替:

with t(last_updated, col) as (select systimestamp, 1 from dual)
SELECT col FROM t WHERE   
last_updated > SYS_EXTRACT_UTC(systimestamp) - TO_DSINTERVAL(:val);

       COL
----------
         1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-09
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多