2016-12-27 73 views
0

我想執行我下面的程序無效的SQL語句,但一直得到錯誤(ORA-00900:無效的SQL語句)ORA-00900:對於Oracle過程

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; 
+1

當你使用'cursor for'循環時,不要顯式地打開/關閉遊標('OPEN usersessiondetail_cur')。另外在這種情況下,絕對不需要使用動態SQL('UPDATE'語句)。 –

+1

動態SQL完全沒用。你爲什麼使用它? –

+1

您是否獲得了錯誤嘗試編譯的程序,還是真的試圖執行它的時候?無論哪種方式,你怎麼做 - 客戶端和命令等?什麼是你得到的完整的錯誤堆棧? (你爲什麼要使用循環,而不是僅僅進行一次更新?你的'run'參數是什麼? –

回答

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動態執行。
  • 打開和合攏遊標語句不與使用遊標循環。
  • 你不需要爲此查詢顯式遊標聲明。
  • 行逐痛苦與遊標循環行UPDATE是不好的做法,並不必要低效相比,基於集的UPDATE語句。
  • 您的程序不使用run參數...
  • ...但光標確實有MACHINE_ID硬編碼字符串。
  • 最後,UPDATE語句實際上並不改變表的狀態,因爲它設置了CLIENT_ID = CLIENT_ID,所以整個過程毫無意義。

除此之外,一切都很好。

我假設您將此作爲測試來理解如何使用動態SQL而不是作爲業務邏輯的實現。但即使是測試,最好寫一段適當的代碼來做一些事情。特別是當你在StackOverflow上與他人分享代碼時。過多的問題發佈代碼會讓人分心,因爲潛在的受訪者不知道應該處理哪些問題。

0

一個更簡單的只用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; 
/