2016-06-08 72 views
2

我使用遊標將表CUT_CALENDAR中的所有記錄移動到SD_CALENDAR(日曆遷移)。我使用SQL Server上的以下光標這樣的:將Cursor語句從SQL Server轉換爲Oracle不起作用

DECLARE @sdCalendarId NUMERIC(20) 
DECLARE @calendarTypId NUMERIC(5) 
DECLARE @name NVARCHAR(35) 
DECLARE @description NVARCHAR(255) 
DECLARE @ptyId NUMERIC(20) 
DECLARE @lockCode NVARCHAR(20) 
DECLARE @dataOwnerId NUMERIC(20) 
DECLARE @cntId NUMERIC(20) 
DECLARE @nonBusinessDaysMonday CHAR(1) 
DECLARE @nonBusinessDaysTuesday CHAR(1) 
DECLARE @nonBusinessDaysWednesday CHAR(1) 
DECLARE @nonBusinessDaysThursday CHAR(1) 
DECLARE @nonBusinessDaysFriday CHAR(1) 
DECLARE @nonBusinessDaysSaturday CHAR(1) 
DECLARE @nonBusinessDaysSunday CHAR(1) 
DECLARE @ccyId NUMERIC(20) 
DECLARE @code NVARCHAR(30) 
DECLARE @version NUMERIC(10) 
DECLARE @seal VARCHAR(255) 
DECLARE @lstUpdTs DATETIME 



DECLARE cursorCutoffCalendar CURSOR FOR 
    SELECT ID, NAME, CALENDAR_TYP_ID,DESCRIPTION,'Y',PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS 
    FROM CUT_CALENDAR 
    WHERE ID != 1 

OPEN cursorCutoffCalendar 
FETCH NEXT FROM cursorCutoffCalendar INTO @sdCalendarId, @calendarTypId, @name, @description, @ptyId, @lockCode, @dataOwnerId, @cntId, @nonBusinessDaysMonday, @nonBusinessDaysTuesday, @nonBusinessDaysWednesday, @nonBusinessDaysThursday, @nonBusinessDaysFriday, @nonBusinessDaysSaturday, @nonBusinessDaysSunday, @nonBusinessDaysMonday, @ccyId, @code, @version, @seal, @lstUpdTs 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    SELECT @sdCalendarId = COALESCE(MAX(ID),1) FROM SD_CALENDAR 

    SET @sdCalendarId = @sdCalendarId + 1 

    INSERT INTO SD_CALENDAR (ID, NAME, CALENDAR_ROLE_ID,DESCRIPTION,USE_IN_CUTOFF,PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS) 
    VALUES(@sdCalendarId, @name, @calendarTypId,@description,'Y',@ptyId,@lockCode,@dataOwnerId,@cntId,@nonBusinessDaysMonday,@nonBusinessDaysTuesday,@nonBusinessDaysWednesday,@nonBusinessDaysThursday,@nonBusinessDaysFriday,@nonBusinessDaysSaturday,@nonBusinessDaysSunday,@ccyId,@code,@version,@seal,@lstUpdTs) 
END 
CLOSE cursorCutoffCalendar 
DEALLOCATE cursorCutoffCalendar 
GO 

因爲我也想支持Oracle體系結構,我想這SqlServer的光標轉換爲以下Oracle光標:

DECLARE v_sdCalendarId NUMERIC(20); 
    v_calendarTypId NUMERIC(5); 
    v_name VARCHAR2(35); 
    v_description VARCHAR2(255); 
    v_ptyId NUMERIC(20); 
    v_lockCode VARCHAR2(20); 
    v_dataOwnerId NUMERIC(20); 
    v_cntId NUMERIC(20); 
    v_nonBusinessDaysMonday CHAR(1); 
    v_nonBusinessDaysTuesday CHAR(1); 
    v_nonBusinessDaysWednesday CHAR(1); 
    v_nonBusinessDaysThursday CHAR(1); 
    v_nonBusinessDaysFriday CHAR(1); 
    v_nonBusinessDaysSaturday CHAR(1); 
    v_nonBusinessDaysSunday CHAR(1); 
    v_ccyId NUMERIC(20); 
    v_code VARCHAR2(30); 
    v_version NUMERIC(10); 
    v_seal VARCHAR(255); 
    v_lstUpdTs DATE; 
    CURSOR cursorCutoffCalendar IS 
     SELECT ID, NAME, CALENDAR_TYP_ID,DESCRIPTION,'Y',PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS 
     FROM CUT_CALENDAR 
     WHERE ID != 1; 

BEGIN 
    FOR calendar IN cursorCutoffCalendar 
    LOOP 
     SELECT COALESCE(MAX(ID),1) into v_sdCalendarId from SD_CALENDAR; 

        INSERT INTO SD_CALENDAR (ID, NAME, CALENDAR_ROLE_ID,DESCRIPTION,USE_IN_CUTOFF,PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS) 
        VALUES(v_sdCalendarId, v_name, v_calendarTypId,v_description,'Y',v_ptyId,v_lockCode,v_dataOwnerId,v_cntId,v_nonBusinessDaysMonday,v_nonBusinessDaysTuesday,v_nonBusinessDaysWednesday,v_nonBusinessDaysThursday,v_nonBusinessDaysFriday,v_nonBusinessDaysSaturday,v_nonBusinessDaysSunday,v_ccyId,v_code,v_version,v_seal,v_lstUpdTs); 
    END LOOP; 
CLOSE cursorCutoffCalendar; 

END; 
/

ORA-01001:無效光標ORA-06512:在第34行

我的oracle遊標腳本有什麼問題?

回答

0

有許多事情錯了你的程序:

  1. 你取一個光標,但你沒有在任何地方存儲的值。這是你錯誤的原因。您需要將值提取到遊標rowtype變量或單個變量中。
  2. 如果您絕對必須通過遊標進行循環,則使用CURSOR FOR LOOP要容易得多。
  3. 您正在使用max(val)+ 1填充(可能)唯一的id列。這不是你應該做的事 - 特別是如果有其他併發事務。相反,你應該使用一個序列,例如:

create sequence sd_calendar_seq 
    START WITH 261 -- something that's higher than the max id of sd_calendar 
    MAXVALUE 999999999999999999999999999 
    MINVALUE 1 
    NOCYCLE 
    CACHE 20 
    NOORDER; 
  • 你並不需要循環光標在所有 - 事實上,這是做它的緩慢方式。您可以使用單個插入語句一舉完成所有工作:
  • insert into sd_calendar (id, 
             name, 
             calendar_role_id, 
             description, 
             use_in_cutoff, 
             pty_id, 
             lock_code, 
             data_owner_id, 
             cnt_id, 
             non_business_days_monday, 
             non_business_days_tuesday, 
             non_business_days_wednesday, 
             non_business_days_thursday, 
             non_business_days_friday, 
             non_business_days_saturday, 
             non_business_days_sunday, 
             ccy_id, 
             code, 
             version, 
             seal, 
             lst_upd_ts) 
        SELECT sd_calendar_seq.nextval, 
         name, 
         calendar_typ_id, 
         description, 
         'Y', 
         pty_id, 
         lock_code, 
         data_owner_id, 
         cnt_id, 
         non_business_days_monday, 
         non_business_days_tuesday, 
         non_business_days_wednesday, 
         non_business_days_thursday, 
         non_business_days_friday, 
         non_business_days_saturday, 
         non_business_days_sunday, 
         ccy_id, 
         code, 
         version, 
         seal, 
         lst_upd_ts 
        from cut_calendar 
        where id != 1; 
    

    看你更新的代碼,還有一些其他問題:

    1. 你選擇到一個變量語法不正確。相反,它應該是:select coalesce(max(id),1) into v_sdcalendarid from sd_calendar;
    2. 您設置變量值的語法不正確。它應該是v_sdcalendarid := v_sdcalendarid + 1;
    3. 現在您已經定義了光標記錄(calendar),您不需要所有的單個變量。另外,您需要更改插入的值以引用記錄字段。
    4. 當您使用循環遊標時,不需要明確地打開或關閉遊標。

    這意味着你的代碼應該是這個樣子:

    declare 
        v_sdcalendarid numeric (20); 
    
        cursor cursorcutoffcalendar 
        is 
        select id, 
          name, 
          calendar_typ_id, 
          description, 
          'Y' use_in_cutoff, 
          pty_id, 
          lock_code, 
          data_owner_id, 
          cnt_id, 
          non_business_days_monday, 
          non_business_days_tuesday, 
          non_business_days_wednesday, 
          non_business_days_thursday, 
          non_business_days_friday, 
          non_business_days_saturday, 
          non_business_days_sunday, 
          ccy_id, 
          code, 
          version, 
          seal, 
          lst_upd_ts 
        from cut_calendar 
        where id != 1; 
    begin 
        for calendar in cursorcutoffcalendar 
        loop 
        select coalesce (max (id), 1) 
        into v_sdcalendarid 
        from sd_calendar; 
    
        v_sdcalendarid := v_sdcalendarid + 1; 
    
        insert into sd_calendar (id, 
              name, 
              calendar_role_id, 
              description, 
              use_in_cutoff, 
              pty_id, 
              lock_code, 
              data_owner_id, 
              cnt_id, 
              non_business_days_monday, 
              non_business_days_tuesday, 
              non_business_days_wednesday, 
              non_business_days_thursday, 
              non_business_days_friday, 
              non_business_days_saturday, 
              non_business_days_sunday, 
              ccy_id, 
              code, 
              version, 
              seal, 
              lst_upd_ts) 
        values  (v_sdcalendarid, 
           calendar.name, 
           calendar.calendartypid, 
           calendar.description, 
           calendar.use_in_cutoff, 
           calendar.ptyid, 
           calendar.lockcode, 
           calendar.dataownerid, 
           calendar.cntid, 
           calendar.nonbusinessdaysmonday, 
           calendar.nonbusinessdaystuesday, 
           calendar.nonbusinessdayswednesday, 
           calendar.nonbusinessdaysthursday, 
           calendar.nonbusinessdaysfriday, 
           calendar.nonbusinessdayssaturday, 
           calendar.nonbusinessdayssunday, 
           calendar.ccyid, 
           calendar.code, 
           calendar.version, 
           calendar.seal, 
           calendar.lstupdts); 
        end loop; 
    end; 
    /
    

    不過,我想HIGHLY在這裏推薦兩件事情:

    1. 使用序列來生成ID值
    2. 在單個插入語句中執行此操作,如上所示。

    如果您不能使用無論出於何種原因序列(爲什麼不呢?),你仍然可以做一些這樣的:

    insert into sd_calendar (id, 
             name, 
             calendar_role_id, 
             description, 
             use_in_cutoff, 
             pty_id, 
             lock_code, 
             data_owner_id, 
             cnt_id, 
             non_business_days_monday, 
             non_business_days_tuesday, 
             non_business_days_wednesday, 
             non_business_days_thursday, 
             non_business_days_friday, 
             non_business_days_saturday, 
             non_business_days_sunday, 
             ccy_id, 
             code, 
             version, 
             seal, 
             lst_upd_ts) 
        select (select coalesce (max (id), 1) from sd_calendar) + rownum id, 
         name, 
         calendar_typ_id, 
         description, 
         'Y', 
         pty_id, 
         lock_code, 
         data_owner_id, 
         cnt_id, 
         non_business_days_monday, 
         non_business_days_tuesday, 
         non_business_days_wednesday, 
         non_business_days_thursday, 
         non_business_days_friday, 
         non_business_days_saturday, 
         non_business_days_sunday, 
         ccy_id, 
         code, 
         version, 
         seal, 
         lst_upd_ts 
        from cut_calendar 
        where id != 1; 
    

    爲什麼我推薦一個SQL語句的方法的原因是,它更容易維護(代碼少得多),更容易測試(您可以自行運行SQL語句以查看將要插入的行),並且它會比光標所對應的循環更快。這是因爲關係數據庫非常擅長處理大量數據 - 這是他們設計的目的。

    然而,當你循環輪光標(做DML基於光標),你正在做的是:

    1. 從PL/SQL引擎,您對SQL引擎調用取一行。
    2. 然後你回到PL/SQL引擎來處理結果。
    3. 然後回到SQL引擎運行DML語句。
    4. 然後回到PL/SQL引擎取下一行
    5. 重複步驟2-4,直到找不到更多的行。

    這是一個非常多的上下文切換。爲什麼不通過使用單個處理整批數據的DML語句來完全避免這種情況。如果你喜歡,你甚至可以將這個語句嵌入到PL/SQL中!

    +0

    我又遇到一個新問題,我已經更新了我的答案,你能再檢查一次嗎? – Boerejef

    +0

    @Boerejef從我上面的回答:'4。當你使用循環遊標時,你不需要明確地打開或關閉遊標。「...所以,刪除關閉遊標語句。出於好奇,爲什麼你仍然堅持使用循環遊標的方法,而不是使用單個插入語句? – Boneist