1. 程式人生 > >Oracle儲存過程書寫規範和技巧

Oracle儲存過程書寫規範和技巧

Ø        變數名全部採用小寫,區域性變數名使用“v_”開頭,輸入引數以“i_開頭,輸出引數以“o_”開頭,輸入輸出引數用io_開頭。所有輸入引數必須顯示宣告

Ø        遊標的命名:遊標統一用字尾 “_cur” 命名

Ø        使用命名的常量以避免硬編碼,使用常量包,常量統一用 cn_ 的字首命名

Ø        當變數代表列時,使用%TYPE屬性,當變數實際上表示資料庫表的某列資料時,為避免資料庫結構修改對變數的影響,應統一使用%TYPE屬性對變數命名

Ø        使用%TYPE以標準化非資料庫變數的宣告

Ø        按照專案制定的檔案組織劃分包內容

Ø        包內的儲存過程及函式的命名必須遵循CPIC制訂的相關規範

Ø        外部查詢的多行資料返回使用遊標進行處理,通過傳遞遊標變數的形式返回資料到外部介面,由外部程式自行FETCH資料。

Ø        開啟遊標前,必須顯式檢查遊標的%ISOPEN屬性。

Ø        使用FETCH語句後,要立即檢查%NOTFOUND屬性,以便正常終止遊標FETCH迴圈。

Ø        無論PL/SQL程式是正常終止還是出錯退出,都要關閉所有已開啟的遊標。在出錯退出時,應該在其異常處理部分管理所有遊標,這可以釋放一部分的系統資源

Ø        儘可能使用顯示遊標,避免使用隱式遊標。

Ø        在需要分割事務以使主事務的提交或者回滾獨立於子事務的提交及回滾時,應使用自治事務

Ø        所有的儲存過程均統一在結束處統一COMMIT或者ROLLBACK

Ø        按照業務邏輯實現功能模組的封裝,將業務規則邏輯集中在更少量的、良好設計的、易於維護的函式或者過程中,不必在每條SQL語句或者每天PL/SQL程式中重複這些邏輯

Ø        基於單一資料表的增、刪、改、查採用標準SP進行封裝,不允許相同邏輯的處理出現在多個SP中

Ø        後臺資料按照邏輯劃分成多個SCHEMA,不同SCHEMA的資料不可互相訪問

Ø        需要相互訪問的表均存放在 ***的SCHEMA中,通過訪問***中的介面表實現跨SCHEMA的資料訪問

Ø        採用公共的API包完成後臺日志資料記錄。(API完成輸出錯誤資訊提示、記錄錯誤資訊內容到資料庫表、系統級的錯誤程式碼及錯誤資訊等)

Ø        後臺日誌的資訊記錄級別包括INFO、WARN、ERROR,其定義以及不同級別日誌的採集標準如下:

       INFO-提示資訊,供開發人員除錯使用,由開發人員自行確定,主要是除錯資訊,程式執行中普通訊息提示。

       WARN-警告資訊,可能導致嚴重錯誤的警告資訊

       ERROR-錯誤資訊,導致系統執行錯誤的資訊。

Ø        所有表操作的錯誤處理部分均應記錄日誌資訊

Ø        凡是涉及到表操作(insert,update,select,delete)的sql語句,都必須進行錯誤捕捉,不能將錯誤帶到後面的語句

Ø        從表中select資料的語句,應嚴格區分NO_DATA_FOUND 和 TOO_MANY_ROWS的錯誤,並將相應錯誤資訊填入錯誤資訊

Ø        NO_DATA_FOUND   多數為查詢條件問題導致無資料返回(使用者級錯誤)

Ø        TOO_MANY_ROWS  應該是資料表內資料異常導致(系統級錯誤)

Ø        所有儲存過程(函式)的統一出口一律在儲存過程的結束部分,不允許中間返回

Ø        在每一個異常處理部分,都要定義WHEN OTHER 子程式,以便捕獲所有沒有顯示處理或其他型別的異常

Ø        所有程式中捕獲到的錯誤,均轉換成對應的errcode,errmsg,通過輸出引數返回給呼叫者,所有儲存過程(函式)結束前應統一捕獲系統異常

Ø        在每個儲存過程(函式)的入口處統一先將返回錯誤程式碼(errCode)設定為42,功能處理成功結束後再將錯誤程式碼(errCode)設定為0(成功),避免程式過程中因錯誤未能正確捕獲,導致功能未能完成,而程式卻成功返回的情況出現

Ø        所有的模組都有錯誤編碼區間,原則上錯誤編碼全域性唯一

Ø        錯誤資訊描述應準確,業務相關的錯誤應將輸入資料拼接到錯誤資訊中。

Ø        錯誤程式碼具體規範見《建行ODS專案ETL-2.1開發規範(公共).doc》

Ø        PL/SQL語句的所有表名、欄位名遵照資料字典的定義,系統保留字、內建函式名、PL/SQL保留字、關鍵字大寫,使用者宣告的識別符號小寫。

Ø        對於子程式、觸發器、包等帶名的程式塊,使用結束標識。

Ø        變數名小寫,區域性變數名使用“v_”開頭,輸入引數以“i_”開頭,輸出引數以“o_”開頭,輸入輸出引數用io_開頭。所有輸入引數必須顯示宣告。

Ø        連線符OR、IN、AND、以及=、<=、>=等前後加上一個空格。 

Ø        對較為複雜的SQL語句加上註釋,說明演算法、功能。 

Ø        註釋風格:註釋單獨成行、放在語句前面。 

       應對不易理解的分支條件表示式加註釋; 

       對重要的計算應說明其功能; 

       過長的函式實現,應將其語句按實現的功能分段加以概括性說明; 

       常量及變數註釋時,應註釋被儲存值的含義(必須),合法取值的範圍

       可採用單行/多行註釋。(-- 或 方式) 

Ø        SQL語句的縮排風格 

       一行有多列,超過80個字元時,基於列對齊原則,採用下行縮排 

       WHERE子句書寫時,每個條件佔一行,語句另起一行時,以保留字或者連線符開始,連線符右對齊。例如:

where       f1 = 1

and       f2 = 2

or      f3 = 3

       INSERT語句,必須書寫欄位,欄位可5個或6個一組。中間用TAB分開

Ø        多表連線時,使用表的別名來引用列。 

Ø        供別的檔案或函式呼叫的函式,絕不應使用全域性變數交換資料; 

Ø        TAB 統一定義為4個空格,建議使用Ultraedit作為SQL書寫工具

Ø        避免巢狀連線。例如:A = B AND B = C AND C = D

Ø        WHERE條件中儘量減少使用常量比較,改用主機變數

Ø        系統可能選擇基於規則的優化器,所以將結果集返回資料量小的表作為驅動表(FROM後邊最後一個表)。

Ø        大量的排序操作影響系統性能,所以儘量減少ORDER BY和GROUP BY排序操作。  如必須使用排序操作,請遵循如下規則

       排序儘量建立在有索引的列上。 

       如結果集不需唯一,使用UNION ALL代替UNION。

Ø        索引的使用

       儘量避免對索引列進行計算。

       儘量注意比較值與索引列資料型別的一致性。 

       對於複合索引,SQL語句必須使用主索引列 

       索引中,儘量避免使用NULL。 

       對於索引的比較,儘量避免使用!= 查詢列和排序列與索引列次序保持一致

Ø        儘量避免相同語句由於書寫格式的不同,而導致多次語法分析。 

Ø        儘量使用共享的SQL語句。

Ø        查詢的WHERE過濾原則,應使過濾記錄數最多的條件放在最前面。 

Ø        任何對列的操作都將導致表掃描,它包括資料庫函式、計算表示式等等,查詢時要儘可能將操作移至等號右邊。 

Ø        IN、OR子句常會使用工作表,使索引失效;如果不產生大量重複值,可以考慮把子句拆開;拆開的子句中應該包含索引。 

Ø        儘量少用巢狀查詢。如必須,請用not exist代替not in子句。

錯誤

SELECT ...... 

  FROM emp 

  WHERE dept_no NOT IN ( SELECT dept_no 

  FROM dept 

  WHERE dept_cat='A');

正確

SELECT ...... 

  FROM emp e 

  WHERE NOT EXISTS ( SELECT 'X' 

  FROM dept 

  WHERE dept_no=e.dept_no 

  AND dept_cat='A'); 

Ø        用多表連線代替EXISTS子句。

錯誤

SELECT ...... 

  FROM emp 

  WHERE EXISTS ( SELECT 'X' 

  FROM dept 

  WHERE dept_no=e.dept_no 

  AND dept_cat='A');

正確

SELECT ...... 

  FROM emp e,dept d 

  WHERE e.dept_no=d.dept_no 

  AND dept_cat='A';

Ø        少用DISTINCT,用EXISTS代替

錯誤

SELECT DISTINCT d.dept_code,d.dept_name 

  FROM dept d ,emp e 

  WHERE e.dept_code=d.dept_code; 

正確

SELECT dept_code,dept_name 

  FROM dept d 

  WHERE EXISTS ( SELECT 'X' 

  FROM emp e 

  WHERE e.dept_code=d.dept_code);

Ø        使用UNION ALL、MINUS、INTERSECT提高效能 

Ø        使用ROWID提高檢索速度。對SELECT得到的單行記錄,需進行DELETE、UPDATE操作時,使用ROWID將會使效率大大提高。 

Ø        使用優化線索機制進行訪問路徑控制。 

Ø        使用cursor時,顯示游標優於隱式游標 。

一:

CREATE OR REPLACE PROCEDURE proc_batch

IS

interactionhour varchar(100);

upcdrname varchar(100);

part_hour varchar(100);

calendar date;

interactionday1 varchar(100);

interactionday varchar(100);

part_day varchar(100);

errmsg  varchar(300);

BEGIN

calendar := sysdate-1/24;

part_hour :=to_char(sysdate-1/24,'hh24');

part_day :=to_char(sysdate-1,'dd');

interactionhour := 'interactionhour'||to_char(calendar,'yyyymm');

interactionday := 'interactionday'||to_char(calendar,'yyyymm');

interactionday1 := 'interactionday1'||to_char(calendar,'yyyymm');

upcdrname := 'upcdr'||to_char(calendar,'yymmdd');

proc_interactionhour (interactionhour,upcdrname ,part_hour ,calendar);

if to_char(sysdate,'hh24')='03' then

proc_interactionday (interactionhour ,interactionday ,interactionday1 ,part_day );

end if;

if to_char(sysdate,'hh24')='04' then

proc_interactiondayshow (interactionday1 ,interactionday );

end if;

insert into appmsg

values('成功執行proc_batch','proc_batch',sysdate);

commit;

   EXCEPTION

     WHEN OTHERS THEN

      rollback;

          errmsg:= substr(sqlerrm,1,300);

          insert into appmsg

          values ('沒有成功執行proc_batch','proc_batch',sysdate);

          commit;

END proc_batch;

/

二:CREATE OR REPLACE PROCEDURE proc_interactionday (interactionhour varchar,interactionday varchar,interactionday1 varchar,part_day varchar)

IS

sqltxt1 varchar(2000);

sqltxt2 varchar(2000);

cur_no number;

cur_val number;

errmsg varchar(300);

BEGIN

sqltxt1 :=' insert into '

               || interactionday

               ||' (rival_no,area_no,calendar) '

               ||' select distinct rival_no,area_no,substr(calendar,1,8) '

               ||' calendar from '

               ||  interactionhour

               ||' partition (part_'

               ||  part_day

               ||' ) ' 

            ||' where 1=1 '

            ||' and substr(rival_no,1,2)=''04'' ';

cur_no:=dbms_sql.open_cursor;

dbms_sql.parse(cur_no,sqltxt1,dbms_sql.native);

cur_val:=dbms_sql.execute(cur_no);

dbms_sql.close_cursor(cur_no);

sqltxt2 :=' insert into '

               ||  interactionday1

               ||' (rival_no,area_no,calendar) '

               ||' select distinct rival_no,area_no,substr(calendar,1,8) '

               ||' calendar from '

               ||  interactionhour

               ||' partition (part_'

               ||  part_day

               ||' ) ' 

               ||' where 1=1 '

               ||' and substr(rival_no,1,3) in (''130'',''131'',''132'',''133'',''134'' ) ';

cur_no:=dbms_sql.open_cursor;

dbms_sql.parse(cur_no,sqltxt2,dbms_sql.native);

cur_val:=dbms_sql.execute(cur_no);

dbms_sql.close_cursor(cur_no);

insert into appmsg

   values('成功執行proc_interactionday','proc_interactionday',sysdate);

   commit;

   EXCEPTION

     WHEN OTHERS THEN

      rollback;

           errmsg := substr(sqlerrm,1,300);

        insert into appmsg

         values('沒有成功執行proc_interactionday,原因是:'||errmsg,'proc_interactionday',sysdate) ;

        commit;

END proc_interactionday;

/

三:CREATE OR REPLACE PROCEDURE proc_interactiondayshow  (interactionday1 varchar,interactionday varchar)

IS

sqltxt1 varchar(2000);

sqltxt2 varchar(2000);

sqltxt3 varchar(2000);

sqltxt4 varchar(2000);

cur_no number;

cur_val number;

errmsg varchar(300);

BEGIN

sqltxt1 :=' insert into '

               ||' interactioncodedayshow(supplier,code,tos,area_name,part_name,total,calendar) '

               ||' select b.supplier, b.code,b.tos,b.area_name,b.part_name,count(*) total,a.calendar '

               ||' from '

               ||  interactionday1

               ||' a, '

               ||'static_interactionno1 b '

               ||' where 1=1 '

相關推薦

Oracle儲存過程書寫規範技巧

Ø        變數名全部採用小寫,區域性變數名使用“v_”開頭,輸入引數以“i_開頭,輸出引數以“o_”開頭,輸入輸出引數用io_開頭。所有輸入引數必須顯示宣告 Ø        遊標的命名:遊標統一用字尾 “_cur” 命名 Ø        使用命名的常量以避免硬編碼,使用常量包,

java面試問題:oracle儲存過程(procedure)函式(function)的區別

oracle儲存過程(procedure)和函式(function)的區別 儲存過程 函式 用於在資料庫中完成特定的操作或者任務(如插入、刪除等) 用於特定的資料(如選擇)

Oralcle儲存過程書寫規範

命名規則: 輸入引數用i作為字首,輸出引數用0來作為開頭.用來與表中欄位區分 引數名的第二個字母根據不同的輸入資料型別確定   //DESCERR 為特殊型別資料,專門作為儲存過程與業務平臺交換異常資料 --Is_shshid 收貨稽核ID --0s_messa

oracle儲存過程中isas 的使用

在儲存過程(PROCEDURE)和函式(FUNCTION)中兩者都可以使用,但是有區別:使用IS 將無法使用除錯模式除錯該儲存過程(函式) 在檢視(VIEW)中只能用AS不能用IS; 在遊標(CURSO

oracle 儲存過程 輸出結果正常查詢不一樣

我的專案是一個學校的教務系統的專案,有很多人蔘與過,因此有很多前人的坑 今天儲存過程裡就一條查詢語句,帶一個返回值,輸出的結果始終和單條查詢語句正常查詢的結果不一樣 儲存過程: CREATE OR REPLACE PROCEDURE PROC( result in out

oracle儲存過程中isas的區別

create or replace procedure imp_person_medical(v_t_table_name varchar2,v_result out varchar2) as /*

sql(join中on與where區別) / NVL函式 / oracle儲存過程中isas區別 / JAVA呼叫資料庫儲存過程

left join :左連線,返回左表中所有的記錄以及右表中連線欄位相等的記錄。 right join :右連線,返回右表中所有的記錄以及左表中連線欄位相等的記錄。 inner join: 內連線,又叫等值連線,只返回兩個表中連線欄位相等的行。 full join:外連線,返回兩個表中的行:left jo

Oracle 儲存過程中傳送郵件,並支援使用者驗證 中文標題內容

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

ORACLE儲存過程變數名表字段名相同

1.事件概述 今天再寫儲存過程使用變數沒注意到問題,導致SQL執行緩慢,找了許久才發現哪裡有問題。 2.發現問題 在儲存過程中執行下圖sql需要20秒左右,執行計劃發現走了全表掃描,而在儲存過程中相同的SQL不會有問題。 然後我單獨把SQL拿出來跑,將變數名替換成真實資料,1秒

Oracle 儲存過程 \ 遊標簡單定義使用

-- Created on 2018/10/12 by 32580 declare -- 定義變數 變數賦值方式為: 變數名 := 值 i INTEGER ; sqls varchar2(500); user_id varchar2(36); l

Oracle 儲存過程、函式的建立呼叫

一、Oracle 建立和呼叫儲存過程 1、基本語法 create or replace procedure update_emp_sal (Name in out type, Name in out type, ... ) is begin end update_emp_

Oracle 函式儲存過程的區別聯絡 總結版

  oracle儲存過程與函式的區別 2017年08月15日 22:49:38 冷月葬花魂iiii 閱讀數:7800更多 個人分類: oracle 定義: 儲存過程(Stored Procedure )是一組為了完成特定功能的SQL 語句集

oracle 儲存過程函式的呼叫方法

一.儲存過程(PROCEDURE)使用過程, 不僅可以簡化客戶端應用程式的開發和維護,而且可以提高應用程式的執行效能.CREATE [OR REPLACE] PROCUDURE procedure_name(arg1 [model1] datatype1, arg2[mod

ORACLE package包中的儲存過程的定義使用

最近的專案中用到了oracle package包中的儲存過程。本文以一個簡單的插入為例,簡述從儲存過程的定義,包括PACKAGE的定義和PACKAGE BODY的定義,到儲存過程的使用。 首先用sql語句建立一個USER_INFO表,sql語句如下:************

ORACLE儲存過程建立呼叫

主要總結下遇到個幾個問題: 1、在業務程式碼執行時,賦值給一個變數,需要使用:=,而不是=; 2、在plsql中執行完建立語句,呼叫報錯 解決辦法: 右鍵編輯儲存過程,在控制檯中可以看到報錯資訊,點選錯誤資訊,可以看到出錯程式碼被標紅 3、在查詢資料

Oracle儲存過程,臨時表的建立、刪除,變數的定義使用

  create or replace procedure Test_GetOaUserInfo  as   --authid current_user操作當前儲存過程的當前使用者,否則提示許可權不足,但是這樣儲存過程這能執行一次   --,或者GRANT CREATE A

hibernate5 呼叫 oracle 儲存過程函式

@Autowired private SessionFactory sessionFactory; //呼叫無返回值儲存過程 public void callProcNoResult(String name){ String sql="{call test_proc_no_result(?)}"; se

關於Oracle中執行儲存過程使用callexec區別說明

在sqlplus中這兩種方法都可以使用:  exec pro_name(引數1..);  call pro_name(引數1..);  區別:  1. 但是exec是sqlplus命令,只能在sqlplus中使用;call為SQL命令,沒有限制.  2. 儲存過程沒有

oracle 儲存過程函式的呼叫方法

一.儲存過程(PROCEDURE) 使用過程, 不僅可以簡化客戶端應用程式的開發和維護,而且可以提高應用程式的執行效能. CREATE [OR REPLACE] PROCUDURE procedure_name (arg1 [model1] datatype1, arg2[m

Oracle儲存過程自定義函式

概述 PL/SQL中的過程和函式(通常稱為子程式)是PL/SQL塊的一種特殊的型別,這種型別的子程式可以以編譯的形式存放在資料庫中,併為後續的程式塊呼叫。 相同點: 完成特定功能的程式 不同點:是否用return語句返回值。 舉個例子: cre