2016-09-08 18 views
0

在庫システムのレポートを生成するクエリを実行しています。クエリには6つのパラメータがあり、そのうちの3つはオプションです。すべてのパラメータが入力されてもクエリは正常に動作しますが、1つまたは複数のオプションのパラメータが省略されている場合、クエリが正しく動作するようにはなりません。SQL LEFT JOINオプションのパラメータを使用したクエリのレポート

重要なパラメータは、@AccountNumber,@Branch,@Departmentおよび@OrderByです。他の3つはオプションですが、@AccountNumberパラメータが必要です。 @Branchが省略された場合は、レポートにそのアカウントのすべての広告枠を表示したいと思います。同様に、@Departmentが省略されていて、@Branchが存在する場合は、そのアカウントのブランチにあるすべての広告枠を表示したいと思います。 3つのパラメータがすべて存在する場合、そのアカウントのブランチおよび部門内のすべてのインベントリが表示されます。 @OrderByが省略された場合、レポートはデフォルトでアカウントの昇順で在庫を注文します。私が使用しているクエリは以下の通りです:

USE database; 
GO 
CREATE PROCEDURE RetrievedList 
    @AccountNumber int, 
    @Branch nvarchar(50), 
    @Department nvarchar(50), 
    @StartDate date, 
    @EndDate date, 
    @OrderBy nvarchar(10) 
AS 

IF @OrderBy = 'Locator' 
BEGIN 
    SELECT [Container].[Acct] AS [Account] 
     ... 
     FROM [File] LEFT JOIN [Container] 
     ON [File].[BoxID] = [Container].[BoxID] 
     WHERE [Container].[Acct] = @AccountNumber 
     AND [Container].[Branch] = @Branch 
     AND [Container].[Dept] = @Department 
     AND [File].[Out_Date] IS NOT NULL 
     AND [File].[Out_Date] BETWEEN @StartDate AND @EndDate 
     ORDER BY [Container].[Loc]; 
END 
ELSE IF @OrderBy = 'Title' 
BEGIN 
    SELECT [Container].[Acct] AS [Account] 
     ... 
     FROM [File] LEFT JOIN [Container] 
     ON [File].[BoxID] = [Container].[BoxID] 
     WHERE [Container].[Acct] = @AccountNumber 
     AND [Container].[Branch] = @Branch 
     AND [Container].[Dept] = @Department 
     AND [File].[Out_Date] IS NOT NULL 
     AND [File].[Out_Date] BETWEEN @StartDate AND @EndDate 
     ORDER BY [File].[Title1]; 
END 
ELSE 
BEGIN 
    SELECT [Container].[Acct] AS [Account] 
     ... 
     FROM [File] LEFT JOIN [Container] 
     ON [File].[BoxID] = [Container].[BoxID] 
     WHERE [Container].[Acct] = @AccountNumber 
     AND [Container].[Branch] = @Branch 
     AND [Container].[Dept] = @Department 
     AND [File].[Out_Date] IS NOT NULL 
     AND [File].[Out_Date] BETWEEN @StartDate AND @EndDate 
     ORDER BY [Container].[Acct], [Container].[Branch], [Container].[Dept], [Container].[BoxNo], [File].[Title1]; 
END 
GO 

私は理由LEFT JOINWHERE [Container].[Branch] = @Branch OR [Container].[Branch] = NULLアプローチを使用することはできませんことを覚えておいてください。予想されるレコードの6倍を返します。

+0

一つの選択肢は、動的SQLを使用することで、 – techspider

+0

この記事はを参照してください。そのフィールドに値がある場合は、必要なフィールドを連結しますいくつかの方法に入りますoこのタイプのクエリを解決し、高いレベルのパフォーマンスを維持します。 http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/ –

答えて

2

この問題のために私の典型的なパターンは次のようにIsNullの演算子を使用している:渡された場合

AND [Container].[Branch] = IsNull(@Branch, [Container].[Branch]) 

は、それがパラメータと比較されます。それ以外の場合は、列をその列と比較します。

+0

このような関数内の列をラップすると、パフォーマンスの面で悲惨な問題が発生する可能性があります。 –

+0

はい、@SeanLangeに同意します - あなたは常にあなたのデータを知る必要があり、これを導入した後にパフォーマンスの問題がある場合は、動的SQLのような何かが良いかもしれません。しかし、このパターンは私を良くしてくれました。 – bassrek

+0

しかし、これは非対応です。それをContainer.Branch = @_Branchまたは@_Branch IS NULLに変更すると、sargabilityが維持されます。 –

0

@bassrekは、あなた自身がJOIN条件でケース式を作成し、本当に必要な値を作成することができます。あなたのクエリで変更されている唯一のものが、同じクエリを3回コピーするのではなく、あなたが望む順序を実行することによって、一連のケース文をあなたの注文書に書かないのはなぜでしょうか?で注文。変更が必要な場合は、ビジネスロジックを維持しやすくなります。

代わりにショーンは、IN演算子を使用し、nullに対処する可能性が示唆するように代わりにパフォーマンスのために自分自身と比較することのもう一つの方法:

ISNULL(@Branch,'') IN ([Container].[Branch],'') 

たとえば、あなたが@Branchを作るために、次の行うことができます、@Department、および@OrderByオプションと3は、単一のステートメントに選択し、すべての組み合わせ:

SELECT [Container].[Acct] AS [Account] 
     ... 
     FROM [File] LEFT JOIN [Container] 
     ON [File].[BoxID] = [Container].[BoxID] 
     WHERE [Container].[Acct] = @AccountNumber 
     AND ISNULL(@Branch,'') IN ([Container].[Branch],'') 
     AND ISNULL(@Department,'') IN ([Container].[Dept],'') 
     AND [File].[Out_Date] IS NOT NULL 
     AND [File].[Out_Date] BETWEEN @StartDate AND @EndDate 
     ORDER BY 
     CASE 
      WHEN ISNULL(@OrderBy,'') = 'Locator' THEN [Container].[Loc] 
      WHEN ISNULL(@OrderBy,'') = 'Title' THEN [File].[Title1] 
      ELSE [Container].[Acct] 
     END 
     ,CASE 
      WHEN LEN(ISNULL(@OrderBy,'')) <> 0 THEN '1' 
      ELSE [Container].[Branch] 
     END 
     ,CASE 
      WHEN LEN(ISNULL(@OrderBy,'')) <> 0 THEN '1' 
      ELSE [Container].[Dept] 
     END 
     ,CASE 
      WHEN LEN(ISNULL(@OrderBy,'')) <> 0 THEN '1' 
      ELSE [Container].[BoxNo] 
     END 
     ,CASE 
      WHEN LEN(ISNULL(@OrderBy,'')) <> 0 THEN '1' 
      ELSE [File].[Title1] 
     END 
関連する問題