0

C# アプリケーションの DataSet に送信するデータを取得するために、以下のストアド プロシージャを作成しました。

ストアド プロシージャのより堅牢な設計を提案していただけますか? これは、レコード セットを返す最良の方法ではないと思います。

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つの異なるテーブルがあります。

4

2 に答える 2

0
  • あなたの構文は有効なようです。
  • ストアド プロシージャ内のカーソルを閉じることはできません。カーソルはクライアントに返されるため、クライアント アプリケーションはカーソルを閉じる必要があります。クライアントがタグに基づく C# アプリケーションであると仮定すると、C# アプリケーションはカーソルを閉じる必要があります。

SYS_REFCURSORアーキテクチャ上、4 つの個別のパラメーターを返すストアド プロシージャを設計することはまれです。特に、ほとんどのクエリが 1 行のデータ ( がテーブルEMP_EMAIL内のキーであると仮定) または少数のデータ行 (場合は、EMPLOYEESたとえば、従業員は複数の住所を持っている場合があります)。EMP_EMAILがテーブルのキーでない場合EMPLOYEES、クライアントがどの住所、どの電話番号、またはどの仕事がどの従業員と関係しているかを把握する方法がわかりません。これはほぼ間違いなくバグです。シングルを返す方がはるかに一般的ですSYS_REFCURSOR多くの行が返される場合はデータベース内の 4 つのテーブルを結合した結果、返される行が 1 つだけであることがわかっている場合はスカラー (場合によってはスカラー型) が返され、本当に必要な場合は 4 つの別個のプロシージャが必要です。 4 つの独立した結果セットが返されました。SYS_REFCURSOR個人的には、電話番号とは別のパラメーターで住所が本当に必要な場合は、コレクションではなくコレクションを返すことを好みOUTますが、C# アプリケーションが 4 つの個別の GUI コントロールを実際に宣言して 4 つを表示すると仮定すると、C# アプリケーションにマップするのが難しくなる可能性があります。結果セットを分離します。

一般的な規則として、何らかの命名規則を使用してパラメーターを識別し、それらを列名および潜在的な列名から分離することを強くお勧めします。そして、アンカー型を使用することをお勧めします。個人的には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_email私の意図は、employeesテーブルの をemp_emailパラメーターと比較することであることは明らかです。emp_emailただし、代わりに、このコードはテーブルの をそれ自体と比較し、NULL でないemployeesテーブルのすべての行を返します。emp_email代わりに、パラメーターに一貫した命名規則を使用する場合

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;

そうすれば、ローカル変数を参照しようとしているときに誤って列名を参照してしまった場合や、その逆の場合はすぐに明確になります。

一般に、すべてのプロシージャをパッケージの一部にすることも強くお勧めします。これは整理に役立ち、関連する手順をまとめてグループ化できます。この場合、この手順を 4 つの別個の手順に分割し、それぞれが 1 つのSYS_REFCURSOR. パッケージを使用すると、カプセル化に役立つパッケージ内のメソッドでのみ使用できるプライベート メソッドを定義できます。また、パッケージ本体ではなくパッケージ仕様を変更する場合にのみ、他のパッケージを再コンパイルする必要があるため、パッケージは依存関係の管理に役立ちます。

于 2012-07-20T18:45:59.340 に答える