2012-07-20 187 views
0

我已經編寫了下面的存儲過程來檢索要發送到我的C#應用​​程序的DataSet的數據。Oracle存儲過程問題

您能否爲我的存儲過程建議一個更強大的設計?我假設這不是返回記錄集的最佳方式。

CREATE OR REPLACE PROCEDURE GET_EMPLOYEE_DATA 
(
    EMPLOYEE_EMAIL IN VARCHAR2, 
    EMP_RECORD_SET1 OUT SYS_REFCURSOR, 
    EMP_RECORD_SET2 OUT SYS_REFCURSOR, 
    EMP_RECORD_SET3 OUT SYS_REFCURSOR, 
    EMP_RECORD_SET4 OUT SYS_REFCURSOR 
) AS 
BEGIN 
    OPEN EMP_RECORD_SET1 FOR 

    SELECT EMPLOYEENAME AS EMP_NAME, 
     EMPLOYEELASTNAME AS EMP_LAST_NAME, 
     EMPLOYEEFIRSTNAME AS EMP_FIRST_NAME 
     FROM EMP.EMPLOYEES 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL 
     ; 

    OPEN EMP_RECORD_SET2 FOR 


     SELECT EMPLOYEEADD AS EMP_ADDRESSESS, 
     EMPLOYEECITY AS EMP_CITY, 
     EMPLOYEE_STATE AS EMP_STATE 
     FROM EMP.EMPLOYEES_ADDRESSES 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL; 

     OPEN EMP_RECORD_SET3 FOR 

     SELECT EMPLOYEEPHONE AS EMP_PHONE, 
     EMPLOYEEEXTENSION AS EMP_EXTENSION 
     FROM EMP.EMPLOYEES_CONTACTS 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL 
     ; 

     OPEN EMP_RECORD_SET4 FOR 

    SELECT EMPLOYEEJOB AS EMP_JOB, 
     EMPLOYEERESPONSIBILITIES AS EMP_RESPONSIBILITIES 
     FROM EMP.EMPLOYEES_DATA 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL 
     ; 


END GET_PROTOCOL_INFO_SP; 

我需要知道我的語法是否正確以及是否應關閉遊標。我有4個不同的表格,在應用程序中調用數據。

+2

歡迎使用StackOverflow:如果您發佈代碼,XML或數據樣本,請**在文本編輯器中突出顯示這些行,然後單擊編輯器工具欄上的「代碼示例」按鈕(「{}」)格式和語法突出顯示它! – 2012-07-20 13:54:07

+0

您在客戶端應用程序中如何處理這些結果?你真的提出4個完全獨立的結果表嗎?或者您是否呈現了員工不同屬性的單一視圖? EMP_EMAIL是這些表中的一個關鍵嗎?或者是否真的有可能在所有4個表中有相同的'EMPLOYEE_EMAIL'多行?如果有多名員工使用同一封電子郵件,您如何確定客戶端的哪個地址/電話等數據與哪位員工有關? – 2012-07-20 16:25:03

+0

謝謝marc_s。 @justin洞穴 - 我需要知道我的語法是否正確,以及我是否應該關閉遊標。是的,我有4個不同的表,其中數據在應用程序中調用 – 2012-07-20 18:14:34

回答

0

似乎是一個足夠合理的SP,如果你想獲得4個不同的數據表。
根據每位員工的預期行數和應用程序需求,您還可以考慮僅檢索一個已加入的數據表。

在任何情況下,你可能需要使用更有意義的名稱爲您的數據表(如Employees_PhonesEmployees_Addresses等)

+0

快速的問題,會有我SYS_REFCURSOR限制?如何在需要時關閉遊標?請編輯我的代碼以抽樣。 – 2012-07-20 14:40:40

0
  • 你的語法似乎是有效的。
  • 無法關閉存儲過程中的遊標。由於遊標正在返回給客戶端,客戶端應用程序負責關閉它們。假設客戶端是基於標籤的C#應用​​程序,C#應用程序將需要關閉遊標。

在結構上,這是不尋常設計一個存儲過程返回4個獨立SYS_REFCURSOR參數特別是其中大多數查詢似乎返回是1行的數據(假設EMP_EMAIL處於EMPLOYEES表中的鍵),或一個少數幾行數據(例如,如果員工可能有多個地址)。如果EMP_EMAIL不是EMPLOYEES表中的關鍵字,我不認爲客戶端有辦法找出哪個地址,哪個電話號碼或哪個工作與哪個員工幾乎肯定是一個錯誤。如果返回許多行,返回標量(可能爲標量類型),如果您知道應該只返回一行,則返回一個由數據庫中的四個表連接而成的單個SYS_REFCURSOR會更常見或者如果您確實需要返回四個獨立的結果集,則需要四個獨立的過程。就個人而言,如果您確實想要使用來自電話號碼的單獨OUT參數中的地址,但如果您的C#應用​​程序真的聲明四個單獨的GUI控件要顯示,則可能更難映射到C#應用程序,所以我寧願返回集合而不是SYS_REFCURSOR四個獨立的結果集。

作爲一般約定,我強烈建議使用某種命名約定來標識參數並將它們與列名和潛在列名分開。我會建議使用錨定類型。我會親自使用P_前綴,像

CREATE OR REPLACE PROCEDURE GET_EMPLOYEE_DATA 
(
    P_EMPLOYEE_EMAIL IN EMP.EMPLOYEES.EMAIL%TYPE, 
    P_EMP_RECORD_SET1 OUT SYS_REFCURSOR, 
    P_EMP_RECORD_SET2 OUT SYS_REFCURSOR, 
    P_EMP_RECORD_SET3 OUT SYS_REFCURSOR, 
    P_EMP_RECORD_SET4 OUT SYS_REFCURSOR 
) 

這樣做的原因命名約定是,當你在一個PL/SQL塊寫SQL語句,標識符首先使用列的名稱解析然後使用局部變量。這導致很多人無意中在他們打算將局部變量與列名進行比較的地方編寫代碼,但最終將列名與自己進行比較。例如,如果我寫這樣的事情

CREATE OR REPLACE PROCEDURE get_employee (
    emp_email IN emp.employees.email%type, 
    rc  OUT sys_refcursor 
) 
AS 
BEGIN 
    OPEN rc 
    FOR select * 
     from emp.employees e 
     where e.emp_email = emp_email; 
END; 

很顯然,我的意圖是將emp_emailemployees表進行比對emp_email參數。但是,此代碼最終會將employees表中的emp_email與自身進行比較,並返回emp_email不爲NULL的表中的每一行。相反,如果我使用的參數

CREATE OR REPLACE PROCEDURE get_employee (
    p_emp_email IN emp.employees.email%type, 
    p_rc  OUT sys_refcursor 
) 
AS 
BEGIN 
    OPEN p_rc 
    FOR select * 
     from emp.employees e 
     where e.emp_email = p_emp_email; 
END; 

一致的命名約定則立即清楚得多,如果我無意中指的是列名時,我打算引用本地變量,反之亦然。

總的來說,我還強烈建議每個程序都是程序包的一部分。這有助於組織,允許您將相關的程序組合在一起。在這種情況下,如果您決定將此程序分成四個獨立的程序,而每個程序都返回一個SYS_REFCURSOR,則此組織將會很有幫助。包允許你定義私有方法,這些私有方法只對封裝中的方法有用,這有助於封裝。並且包幫助依賴管理,因爲當你改變包規範而不是包體時,其他包只需要重新編譯。