1. 程式人生 > >儲存過程+巢狀遊標結合使用的例項

儲存過程+巢狀遊標結合使用的例項

上週接了一個新任務——寫儲存過程,我以前可不知道這玩意怎麼寫,上週用了一個星期琢磨了一下然後終於給弄出來了,資料庫用的是Oracle,需求是說要每天定時去處理大批量的資料,用儲存過程處理好了存在中間表裡面,然後專案平臺就直接取中間表的資料就OK,因為目前而言我們是以XX平臺為基礎的二次開發,很多開發具有侷限性,對於大量的資料處理全都是原生sql多表聯查各種複雜查詢出來,效率特別低,速度特慢,所以就有了這麼一個任務了。個人建議還是使用PL/SQl比較方便。我首先就是寫一個入口,所有其他儲存過程呼叫都從這個入口開始:

第一步:寫一個儲存過程入口

我這邊是執行所有ETL開頭的儲存過程

create or replace procedure START_ETL is
   cursor procs is select object_name as pn from user_procedures where object_name like 'ETL%';
   proc procs%rowtype;
begin
   for proc in procs loop
     execute immediate 'begin '||proc.pn||'; end;';
  -- dbms_output.put_line(proc.pn);
   end loop;   
end START_ETL;

第二步:寫一個定時器

begin
  sys.dbms_job.submit(job => :job,
                      what => 'begin
  start_etl;
end;',
                      next_date => to_date('30-10-2017 17:10:00', 'dd-mm-yyyy hh24:mi:ss'),
                      interval => 'sysdate+1/24/3');
  commit;
end;
/
我這裡是每隔sysdate+1/24/3也就是20分鐘執行一次的,這個定時器就是在DBMS_Jobs下面建立的

第三步:編寫處理資料的儲存過程

基本上就可以了,我是用了兩層遊標巢狀遍歷,把執行過程情況寫入日誌表中,這樣多個儲存過程執行的時候方便定位問題所在,另外,寫完儲存過程之後最好就是先除錯一下,選中儲存過程右擊會出現test測試,點選進入除錯頁面,具體怎麼除錯可以百度一下都有的,謝謝

create or replace procedure ETL_NON_OIL_SALES_PROC is
   seq_log integer;   -- 日誌表序列
   seq_theme_log integer;--主題日誌序列
   seq_theme integer;  --主題表序列
   stationcode varchar2(8);  --油站編號
   stationname varchar2(30); --油站名稱
   --定義主題遊標

   cursor etl_theme_cur is select * from (SELECT
       T4.SITE_CODE  AS STATION_CODE,
       T4.STATION_NAME,
       T4.DEPTID,
       T4.DEPTNAME,
       T4.ITEMNAME,
       T4.ITEMID,
       T4.TOTAL   AS SALES_AMOUNT,
       T4.QTY,
       T4.DAY_BATCH_ID,
       T4.DAY_BATCH_DATE,
       S.ORG_CODE        AS COMPANYID,
       S.ORG_ABBR        AS COMPANY
  from ...........此處sql太長,省略後續部分); --定義遊標,該遊標指向查詢結果
 rowresult etl_theme_cur%rowtype;  --宣告行型別變數rowresult 
 
 --定義油站編號的遊標
  cursor etl_org_cur is select site_code,org_abbr from sys_org where org_type='Z';
  rowres etl_org_cur%rowtype;   
 
begin
    select etl_seq.nextval into seq_log from dual;
    insert into etl_proc_log values(seq_log,sysdate,null,'ETL_NON_OIL_SALES_PROC',null);  --儲存過程執行開始日誌
    open etl_org_cur;  --開啟油站遊標
    loop
      fetch etl_org_cur into rowres;  --取出油站遊標的值放入行型別中
      exit when etl_org_cur%notfound;
      select rowres.site_code into stationcode from dual; --給變數賦值
      select rowres.org_abbr into stationname from dual;
      
      
      select etl_seq.nextval into seq_theme_log from dual;  --給主題日誌序列賦值
      insert into etl_theme_log values(seq_theme_log,'ETL_NON_OIL_SALES',sysdate,null,rowres.site_code,rowres.org_abbr,null);  --主題日誌開始
        open etl_theme_cur;  --開啟主題遊標
        loop            
            select etl_seq.nextval into seq_theme from dual;   --給主題序列賦值
            fetch etl_theme_cur into rowresult; --將遊標中的值賦給rowresult
            exit when etl_theme_cur%notfound;--判斷:遊標不存在時跳出迴圈
            
            IF rowres.site_code = rowresult.station_code THEN  --判斷主題資料
                delete from etl_non_oil_sales where id=seq_theme;
                insert into etl_non_oil_sales values(seq_theme,rowresult.station_code,rowresult.station_name,rowresult.deptid,rowresult.deptname,
                rowresult.itemname,rowresult.itemid,rowresult.sales_amount,rowresult.qty,rowresult.day_batch_date,rowresult.day_batch_id,
               rowresult.companyid,rowresult.company);
               update etl_theme_log set end_time=sysdate where id=seq_theme_log;
            end if;
         end loop;
         close etl_theme_cur;
         end loop;
     close etl_org_cur;
  
     update etl_proc_log set end_time=sysdate where id=seq_log;
end ETL_NON_OIL_SALES_PROC;