【问题标题】:ORA-00900: invalid SQL statement for Oracle ProcedureORA-00900: Oracle 过程的 SQL 语句无效
【发布时间】:2017-05-12 05:45:11
【问题描述】:

我正在尝试执行下面的过程,但一直出错(ORA-00900:无效的 SQL 语句)

CREATE OR REPLACE PROCEDURE RESETUSERSESSION (run IN VARCHAR2)
IS    
    cursor usersessiondetail_cur IS    
          SELECT usd.CLIENTID,usd.OPERID,usd.REGISTER,usd.MACHINE_ID,usd.SESSIONNUMBER
          FROM cashiering_dev.CSH_USER usr, cashiering_dev.CSH_USERSESSIONDETAIL usd
          WHERE usr.clientid = usd.clientid 
          AND usr.operid = usd.operid
          AND usr.register = usd.register
          AND usr.machine_id = usd.machine_id 
          AND usr.sessionnumber = usd.sessionnumber
          AND usr.Machine_ID = 'basrytest'
          AND usd.LOGOFFDATETIME IS NULL;


 BEGIN
      OPEN usersessiondetail_cur;      

        FOR vItems in usersessiondetail_cur
        LOOP
           EXECUTE IMMEDIATE 'UPDATE csh_UserSessionDetail 
                         SET ClientID =vItems.CLIENTID 
                        WHERE ClientID =vItems.CLIENTID 
                         AND OperID =vItems.OPERID 
                         AND Register =vItems.REGISTER 
                         AND Machine_ID =vItems.MACHINE_ID 
                         AND SessionNumber =vItems.SESSIONNUMBER';                     
       END LOOP;

      CLOSE usersessiondetail_cur;



END;

【问题讨论】:

  • 当您使用cursor for 循环时,不要显式打开/关闭游标 (OPEN usersessiondetail_cur)。另外,在这种情况下,绝对不需要使用动态 SQL('UPDATE' 语句)。
  • 动态SQL完全没用。你为什么用它?
  • 您是在尝试编译过程时遇到错误,还是在尝试执行过程时遇到错误?无论哪种方式,你是怎么做的 - 哪个客户端和命令等?你得到的完整错误堆栈是什么? (为什么你完全使用循环,而不是只进行一次更新?你的run 参数是什么?)

标签: oracle stored-procedures plsql cursor dynamic-sql


【解决方案1】:

您的 SQL 无效,因为执行动态 SQL 字符串时游标投影名称不在范围内。你需要像这样使用占位符:

   FOR vItems in usersessiondetail_cur
    LOOP
       EXECUTE IMMEDIATE 'UPDATE csh_UserSessionDetail 
                     SET ClientID = :p1
                    WHERE ClientID = :p2 
                     AND OperID = :p3
                     AND Register = :p4 
                     AND Machine_ID = :p5 
                     AND SessionNumber = :p6' 
           using vItems.CLIENTID 
                 , vItems.CLIENTID 
                , vItems.OPERID 
                , Items.REGISTER 
                , vItems.MACHINE_ID 
                , vItems.SESSIONNUMBER;                     
   END LOOP;

您的动态代码不是匿名 PL/SQL 块或 CALL 语句,因此参数是按位置而不是名称传递的,这意味着您必须传递 vItems.CLIENTID 两次。 Find out more.

其他意见

  • 首先,绝对不需要为此 SQL 实现动态执行。
  • OPEN 和 CLOSE 游标语句不与 FOR 游标循环一起使用。
  • 此查询不需要显式游标声明。
  • 与基于集合的 UPDATE 语句相比,使用游标循环的逐行执行 UPDATE 是不好的做法,而且效率低下。
  • 您的过程没有使用run 参数...
  • ... 但光标确实有 MACHINE_ID 的硬编码字符串。
  • 最后,UPDATE 语句实际上并没有改变表的状态,因为它设置了 CLIENT_ID = CLIENT_ID,所以整个过程毫无意义。

除此之外,一切都很好。

我假设您写这篇文章是为了测试了解如何使用动态 SQL,而不是作为业务逻辑的实现。但即使这是一个测试,最好编写一段适当的代码来做某事。尤其是当您在 StackOverflow 上与他人共享代码时。发布有这么多问题的代码会分散注意力,因为潜在的受访者不知道要解决哪个问题。

【讨论】:

    【解决方案2】:

    仅使用 FOR 循环的更简单的方法。在这种情况下,我们不需要打开关闭游标,因为这是由 Oracle 内部处理的。另外我不明白是否需要再次更新客户端 ID。如果我们在 where 子句中选择客户端 ID,则更新没有意义。无论如何享受:)

    CREATE OR REPLACE
    PROCEDURE RESETUSERSESSION(
        run IN VARCHAR2)
    AS
    BEGIN
      FOR vItems IN
      (SELECT usd.CLIENTID,
        usd.OPERID,
        usd.REGISTER,
        usd.MACHINE_ID,
        usd.SESSIONNUMBER
      FROM cashiering_dev.CSH_USER usr,
        cashiering_dev.CSH_USERSESSIONDETAIL usd
      WHERE usr.clientid      = usd.clientid
      AND usr.operid          = usd.operid
      AND usr.register        = usd.register
      AND usr.machine_id      = usd.machine_id
      AND usr.sessionnumber   = usd.sessionnumber
      AND usr.machine_id      = 'basrytest'
      AND usd.LOGOFFDATETIME IS NULL
      )
      LOOP
        UPDATE csh_UserSessionDetail
        SET ClientID      =vItems.CLIENTID
        WHERE ClientID    =vItems.CLIENTID
        AND OperID        =vItems.OPERID
        AND Register      =vItems.REGISTER
        AND Machine_ID    =vItems.MACHINE_ID
        AND SessionNumber =vItems.SESSIONNUMBER;
      END LOOP;
    END;
    /
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-29
      • 2011-07-17
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 2019-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多