oracle 動態SQL在儲存過程中的使用
1、 靜態SQL和動態SQL
Oracle編譯PL/SQL程式塊分為兩個種(其它SQL程式碼塊包括儲存過程也是如此):
其一為前期聯編(early binding),即SQL語句在程式編譯期間就已經確定,大多數的編譯情況屬於這種型別;另外一種是後期聯編(late binding),即SQL語句只有在執行階段才能建立,例如當查詢條件為使用者輸入時,那麼Oracle的SQL引擎就無法在編譯期對該程式語句進行確定,只能在使用者輸入一定的查詢條件後才能提交給SQL引擎進行處理。通常,靜態SQL採用前一種編譯方式,而動態SQL採用後一種編譯方式。
動態SQL的兩種寫法:
(1) Excute immediate
(2) v_sqlvarchar2(4000); v_month_name varchar2(10); …… v_sql:=’……’; execute immediatev_sql;
v_month_name varchar2(10);
v_sql varchar2(4000);
v_sql:=’insert into tablename(c1,c2,……,cn) select '||v_month_name||', short_name,……from tablename2’;
execute
2、使用動態sql的業務場景
需求是根據傳入的日期,取出年份v_year和月份v_month值,然後根據業務規則來查出對應的承租率返回,然後組成資料錄入到一個新的報表表裡面去;
因為年份欄位有一個,可以用where欄位直接判斷,但是月份資料有12個欄位,而且每次傳入的日期獲取的月份數值不一定一致,所以按照比較笨的辦法是需要if else 連續判斷12次才能囊括所有的月份欄位的,這樣儲存過程就會非常冗餘笨重而且不易閱讀。
所以需要找一個新的辦法來處理,避免做連續12個if else的判斷,這裡可以採用動態sql,也就是自動根據傳入日期來組織去查表中的哪個月份欄位和年份欄位。
3、儲存過程使用動態sql示例
createorreplaceprocedure BIS_PROJECT_BUDGET(P_DATE inDATE) is v_date varchar2(10); v_year varchar2(10); v_month varchar2(10); v_month_name varchar2(10); v_sql varchar2(4000); begin --取當日的上個月的最後一天每個月首日統計上個月 select to_char((last_day(add_months(P_DATE,-1))),'yyyy-mm-dd') last_day , to_char((last_day(add_months(P_DATE,-1))),'yyyy') years, to_char((last_day(add_months(P_DATE,-1))),'mm') months into v_date,v_year,v_month from dual; select casewhen v_month='01'then'bt.JAN_KPI' when v_month='02'then'bt.FEB_KPI' when v_month='03'then'bt.MAR_KPI' when v_month='04'then'bt.APR_KPI' when v_month='05'then'bt.MAY_KPI' when v_month='06'then'bt.JUN_KPI' when v_month='07'then'bt.JUL_KPI' when v_month='08'then'bt.AUG_KPI' when v_month='09'then'bt.SEP_KPI' when v_month='10'then'bt.OCT_KPI' when v_month='11'then'bt.NOV_KPI' else'DEC_KPI'endinto v_month_name from dual; delete BIS_SECOND_ZS_PRO where PRO_MONTH=to_number(v_month) and PRO_YEAR = v_year; commit; v_sql:= ' insert into BIS_SECOND_ZS_PRO bp( BIS_SECOND_ZS_PRO_ID , bis_project_id, PRO_YEAR, PRO_MONTH, EMPTY_PRE, BUDGETYEAR_MONTH, CREATOR, CREATED_DATE, RECORD_VERSION ) select sys_guid(), m.bis_project_id, '||v_year||' as years, to_number('||v_month||') as months, m.budget_month, y.budget_year, ''system'', sysdate, dbms_random.value(0,100000) from ( select r.bis_project_id, nvl(decode(r.total_square,0,0,round(('||v_month_name||' - r.open_square/r.total_square)*r.total_square,2)),0) budget_month from (select pt.bis_project_id, pt.short_name, pt.total_square, nvl(sum(af.open_square_total),0) open_square from (select p.bis_project_id, p.short_name, nvl(sum(vf.rent_square_total),0) total_square from bis_project p left join vw_bis_mall_floor_summary vf on p.bis_project_id = vf.bis_project_id where p.is_business_project = ''1'' and p.oper_status = ''2'' group by p.bis_project_id,p.short_name) pt, rep_agg_floor_month af where 1 = 1 and pt.bis_project_id = af.bis_project_id and af.store_type = ''1'' and af.agg_year = '||v_year||' and af.agg_month = to_number('||v_month||') group by pt.bis_project_id,pt.short_name,pt.total_square) r, bis_project_target bt where 1=1 and r.bis_project_id = bt.bis_project_id(+) ) m, ( select r.bis_project_id, nvl(decode(r.total_square,0,0,round(('||v_month_name||' - r.open_square/r.total_square)*r.total_square,2)),0)+r.off_square budget_year from (select pt.bis_project_id, pt.short_name, pt.total_square, af.agg_month, af.agg_year, nvl(sum(af.open_square_total),0) open_square, nvl(sum(af.off_square_total),0) off_square from (select p.bis_project_id, p.short_name, nvl(sum(vf.rent_square_total),0) total_square from bis_project p left join vw_bis_mall_floor_summary vf on p.bis_project_id = vf.bis_project_id where p.is_business_project = ''1'' and p.oper_status = ''2'' group by p.bis_project_id,p.short_name) pt,rep_agg_floor_month af where 1 = 1 and pt.bis_project_id = af.bis_project_id and af.store_type = ''1'' and af.agg_year = '||v_year||' and af.agg_month = ''1'' group by pt.bis_project_id,pt.short_name,pt.total_square,af.agg_month,af.agg_year) r,bis_project_target bt where r.bis_project_id = bt.bis_project_id(+)) y where m.bis_project_id = y.bis_project_id '; executeimmediate v_sql; -- v_sql:='select 1 as a from dual;'; commit; EXCEPTION -- 異常處理部份 WHENOTHERSTHEN dbms_output.put_line('insertBisSecondZsPro 錯誤:' || SQLERRM); null; end BIS_PROJECT_BUDGET; |