6

SQL Server 2005 を使用しています。すべてのデータ アクセスは、ストアド プロシージャを介して行われます。セレクション ストアド プロシージャは、常に複数の結果セットを返します。

例えば:

CREATE PROCEDURE hd_invoice_select(@id INT) AS
    SELECT * FROM Invoice WHERE InvoiceID = @id
    SELECT * FROM InvoiceItem WHERE InvoiceID = @id
    SELECT * FROM InvoiceComments WHERE InvoiceID = @id
    RETURN

アプリケーションのデータ アクセス レイヤーは、結果に基づいてオブジェクト グラフを作成します (O/R マッパー スタイル)。

私が抱えている問題は、さまざまな請求書選択ストアド プロシージャがあることです。それらはすべて同じ構造を返しますが、選択基準が異なるだけです。たとえば、私も持っています:

CREATE PROCEDURE hd_invoice_selectAllForCustomer(@customerID INT) AS
    SELECT * FROM Invoice WHERE CustomerID = @customerID
    SELECT * FROM InvoiceItem WHERE InvoiceID IN 
        (SELECT InvoiceID FROM Invoice WHERE CustomerID = @customerID)
    SELECT * FROM InvoiceComments WHERE InvoiceID = @id
        (SELECT InvoiceID FROM Invoice WHERE CustomerID = @customerID)
    RETURN

そして、私は次のような他の多くを持っています:

hd_invoice_selectActive()
hd_invoice_selectOverdue()
hd_invoice_selectForMonth(@year INT, @month INT)

私は多くの概念(顧客、従業員など)に対して同じパターンを持っています

大量のコードをコピーすることになり、メンテナンスは本当に大変です。コンセプトの「構造」が変わると、すべてのプロセスを修正する必要があり、非常にエラーが発生しやすくなります。

私の質問は次のとおりです。シナリオでコードを再利用する最良の方法は何ですか?

一時テーブルを使用するソリューションを考え出しました。しかし、それはあまりエレガントではありません。アイデアを共有させていただきます。必要に応じて、ソリューションの詳細を今後の投稿に投稿し、そのアプローチに関するコメントをお待ちしております。

ありがとう

4

10 に答える 10

2

これは別のアプローチであるため、2番目の回答として投稿します。SQL Server 2008 を使用している場合:

CREATE TYPE InvoiceListTableType AS TABLE 
(
    InvoiceId INT
);
GO

CREATE PROCEDURE hd_invoice_selectFromTempTable
(
    @InvoiceList InvoiceListTableType READONLY
)
AS
BEGIN
    SELECT * FROM Invoice WHERE InvoiceID IN
        (SELECT InvoiceId FROM @InvoiceList)

    SELECT * FROM InvoiceItem WHERE InvoiceID IN 
        (SELECT InvoiceId FROM @InvoiceList)

    SELECT * FROM InvoiceComments WHERE InvoiceID IN
        (SELECT InvoiceId FROM @InvoiceList)

    RETURN
END
GO

CREATE PROCEDURE hd_invoice_select(@id INT) AS
BEGIN
    DECLARE @InvoiceList AS InvoiceListTableType;

    SELECT id AS ID 
        INTO @InvoiceList

    EXEC hd_invoice_selectFromTempTable(@InvoiceList)
    RETURN
END
GO

CREATE PROCEDURE hd_invoice_selectAllForCustomer(@customerID INT) AS
BEGIN
    DECLARE @InvoiceList AS InvoiceListTableType;

    SELECT invoiceID as ID
        INTO @InvoiceList
        FROM Invoice WHERE CustomerID = @customerID

    EXEC hd_invoice_selectFromTempTable(@InvoiceList)
    RETURN
END
GO

CREATE PROCEDURE hd_invoice_selectAllActive AS
BEGIN
    DECLARE @InvoiceList AS InvoiceListTableType;

    SELECT invoiceID as ID
        INTO @InvoiceList
        FROM Invoice WHERE Status = 10002

    EXEC hd_invoice_selectFromTempTable(@InvoiceList)
    RETURN
END
GO
于 2009-07-28T14:33:54.680 に答える
2

この特定のシナリオの「最善の」方法は、何らかのコード生成を使用することです。ある種の規則を考え出し、それをコード ジェネレーターにプラグインします。

于 2009-07-14T16:01:20.140 に答える
1

メイン プロシージャのパラメータ リストに複数のクエリ パラメータ タイプを入れてみましたか? Invoice テーブルをカバーするために proc を作成しただけです。追加のテーブル用に拡張する必要があります。

CREATE PROCEDURE hd_invoice_select
(
    @id INT = NULL
    , @customerId INT = NULL
) AS
BEGIN
    SELECT * 
        FROM Invoice 
        WHERE 
            (
                @id IS NULL
                OR InvoiceID = @id
            )
            AND (
                @customerId IS NULL
                OR CustomerID = @customerId
            )
    RETURN
END

このプロセスは、@id と @customerId を NULL として送信するか、@id に基づく特定の InvoiceID に対して @customerId を NULL として送信する (またはすべて一緒に残す) か、または @customerId に基づく特定の顧客に対して、NULL として送信することにより、広くオープンに呼び出すことができます。 @id を NULL にするか、クエリから除外します。

また、ビューとテーブル値のユーザー定義関数も確認する必要があります。これらを proc に配置して、一部のロジックを proc から切り離してラップし、それらを 1 か所で共有および管理できるようにすることができます。ビュー/関数にロジックの一部を含めることで、クエリ ウィンドウ内のデータをテーブルのように処理することもできます。

于 2009-07-14T16:22:46.757 に答える
0

これは、ストアドプロシージャの主な問題の1つであり、人々がそれらを気に入らない理由です。

私はそれを回避する方法を見つけたり見たりしたことがありません。

于 2009-07-14T15:56:30.680 に答える
0

以前に一時テーブル アプローチを使用したアプリケーションを継承しましたが、非常に面倒であることに同意します。

そのプロジェクトでは、必要な「オブジェクト」を含むビューに置き換えることで多くの一時テーブルを削除することができ、ストアド プロシージャを更新してそれらのビューからクエリを実行しました。

おそらく、それはあなたの状況でもうまくいくかもしれません。

于 2009-07-14T16:09:09.500 に答える
0

結合の使い方を学ぶ必要があるかもしれません。3 つのテーブルの基本的な結合をビューに配置し、さまざまなパラメーターを処理する sp を使用してクエリを実行することができます。また、一般的に、運用コードでは select * ever を使用しないでください。その状況で実際に必要ないくつかの列のみを返すと、システム全体のパフォーマンスが向上します。さらに、人々があなたの構造を変えたときに、意図しない結果が生じることはありません.

于 2009-07-14T17:20:32.647 に答える
0

基本的な CRUD のために、コード ジェネレーターによって生成されたストアド プロシージャを使い始めました。レポートや複雑な SQL 作業にストアド プロシージャを使用しています。

あなたの質問とは関係のない提案もあります-IN句を使用する代わりに、SQLステートメントでEXISTS句を使用してください。

于 2009-07-14T16:01:00.780 に答える