【问题标题】:Running Oracle sql script from java gives SQLSyntaxErrorException: ORA-00900: invalid SQL statement从 java 运行 Oracle sql 脚本会给出 SQLSyntaxErrorException: ORA-00900: invalid SQL statement
【发布时间】:2014-01-09 10:40:24
【问题描述】:

我正在使用 Oracle 11g,我正在通过 java 代码执行 Oracle sql 脚本。我的 SQL 脚本可能包含 SQL 语句(DDL 或 DML)或 PL/SQL 块,所以我不想在我的 java 代码中解析脚本,而是使用This solution 一次执行完整的脚本。以下是示例代码,其中SQLExec 类在ant jar 中。

此解决方案适用于大多数情况,但如果 sql 脚本包含 create or replace trigger 它会失败并显示 java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement。我还指定了失败的 sql 脚本的 sn-p。

请注意,如果我通过 SQL Developer 运行相同的脚本,它运行良好。

以下是 Java 代码:

private void executeSql(String sqlFilePath) {
    final class SqlExecuter extends SQLExec {
        public SqlExecuter() {
            Project project = new Project();
            project.init();
            setProject(project);
            setTaskType("sql");
            setTaskName("sql");
        }
    }

    SqlExecuter executer = new SqlExecuter();
    executer.setSrc(new File(sqlFilePath));
    executer.setDriver(args.getDriver());
    executer.setPassword(args.getPwd());
    executer.setUserid(args.getUser());
    executer.setUrl(args.getUrl());
    executer.execute();
}

SQL 脚本 sn-p:

......
......
CREATE OR REPLACE TRIGGER MY_TRG
   BEFORE INSERT ON MY_TABLE
   FOR EACH ROW
   BEGIN
    :NEW.MYNUMBER := MY_SEQUENCENUM.NEXTVAL;
   END;

以下是异常跟踪:

Exception in thread "main" java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement

    at org.apache.tools.ant.taskdefs.SQLExec.execute(SQLExec.java:398)
    at com.kuldeep.OracleConnectionTest.executeSql(OracleConnectionTest.java:160)
    at com.kuldeep.OracleConnectionTest.main(OracleConnectionTest.java:25)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement

    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
    at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:194)
    at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1000)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
    at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1882)
    at oracle.jdbc.driver.OracleStatement.execute(OracleStatement.java:1847)
    at oracle.jdbc.driver.OracleStatementWrapper.execute(OracleStatementWrapper.java:301)
    at org.apache.tools.ant.taskdefs.SQLExec.execSQL(SQLExec.java:499)
    at org.apache.tools.ant.taskdefs.SQLExec.runStatements(SQLExec.java:470)
    at org.apache.tools.ant.taskdefs.SQLExec$Transaction.runTransaction(SQLExec.java:664)
    at org.apache.tools.ant.taskdefs.SQLExec$Transaction.access$000(SQLExec.java:627)
    at org.apache.tools.ant.taskdefs.SQLExec.execute(SQLExec.java:370)

【问题讨论】:

    标签: java sql oracle ant plsql


    【解决方案1】:

    还可以在执行语句中添加分隔符,如下:

    ......
    ......
    DELIMITER $$ 
    
    CREATE OR REPLACE TRIGGER MY_TRG
       BEFORE INSERT ON MY_TABLE
       FOR EACH ROW
       BEGIN
        :NEW.MYNUMBER := MY_SEQUENCENUM.NEXTVAL;
       END; $$
    ......
    

    我也将脚本的最后部分留给触发器和过程,因为分隔符被继续使用。 这对我有用。由 SQL Developer 的迁移工具提供。

    【讨论】:

      【解决方案2】:

      正如@Reza Goodarzi 提到的,无效的 SQL 语句的原因是分号被用作语句分隔符。因此,为了解决我的问题,我用slash(/) 作为分隔符分隔每个语句,并遵循我自己创建的这些规则:

      1. 每个 SQL 语句(不是 PL/SQL 块的一部分)和 PL/SQL 块必须以新行中的正斜杠 (/) 结尾。

      2. SQL 语句(不是 PL/SQL 块的一部分)不应以分号 (;) 结尾。我刚刚从语句末尾删除了分号。

      3. 对于 PL/SQL 块,不要从块的末尾以及块中包含的任何语句中删除分号 (;)。

      通过在我的 SQL 脚本中进行这些更改,我执行(使用 jdbc)每个 PL/SQL 块 和每个 SQL 语句(不是 PL/SQL 块的一部分)一次通过自己解析文件而不是使用 SQLExec 或任何其他外部 api/库。

      【讨论】:

        【解决方案3】:

        在documentation 中写道:

        可以提供多个语句,用分号(或定义的分隔符)分隔。

        因此,使用分号字符 (;) 作为默认分隔符,SQLEXEC 将脚本的 CREATE TRIGGER 语句解释为两个语句,并给出此错误消息作为结果。

        【讨论】:

        • 好的,该语句中的分号有效,但 SQLExec api 将其视为语句分隔符,这是否意味着我不能在这里使用 SQLExec?我在其他方法中也面临几乎相同的问题,例如 ScriptRunner ibatis.apache.org/docs/java/dev/com/ibatis/common/jdbc/…
        • 你可以调用setDelimiter()来定义另一个不干扰任何东西的分隔符;例如|.
        • 试过这个executer.setDelimiter("|");并用|分隔sql语句,但仍然是同样的错误:(
        • 很可能是因为在源文件中,您仍然使用; 作为分隔符。
        • 我想我不能删除分号,因为它们是有效的(并且可能是必需的),因为它是从 SQL Developer 执行的。这是否意味着我要运行的所有 SQL 脚本都必须修改?如果是这样的话,通过java代码运行它们有什么意义,有人可以通过SQL Developer / SQL Plus运行它们。 :(
        【解决方案4】:

        我认为您需要更改触发器以设置新 ID

        create or replace trigger MY_TRG
        BEFORE insert MY_TABLE
        for each row
        begin
          if (:new.MYNUMBER  is null) then
            select MY_SEQUENCENUM.nextval
            into :new.MYNUMBER 
            from DUAL;
          end if;
        end;
        /
        

        或者这个:

        create or replace trigger TG_BIU_TABLE1
        before insert or update on TABLE1
        for each row
        begin
            if (:new.ID1 is null) then
                select SQ_TABLE1.nextval
                into :new.ID1
                from DUAL
            end if
        end
        /
        

        【讨论】:

        • 这是否意味着我的触发器创建不正确?但它确实适用于 SQL Developer。为什么会这样?
        • 您的 Oracle 版本是多少?
        • 我的Oracle版本是11.2.0.3.0
        • 我尝试按照您所说的更改触发器,但仍然遇到相同的异常。
        • 请执行这个-> select object_name from dba_objects where object_type = 'TRIGGER' and status = 'INVALID';
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-15
        • 2019-08-30
        • 2010-09-17
        • 1970-01-01
        • 1970-01-01
        • 2017-05-12
        • 1970-01-01
        相关资源
        最近更新 更多