SQL LEFT JOIN带有可选参数的查询报告

时间:2016-09-08 16:33:50

标签: sql sql-server

我正在运行一个为库存系统生成报告的查询。该查询包含6个参数,其中3个是可选的。如果输入了所有参数,查询工作正常,但是当省略一个或多个可选参数时,我无法使查询正常运行。

重要参数包括@AccountNumber@Branch@Department@OrderBy@AccountNumber参数是必需的,而其他三个是可选的。如果省略@Branch,我希望报告显示该帐户中的所有广告资源。同样,如果省略@Department@Branch存在,我想显示该帐户分支中的所有广告资源。如果存在所有三个参数,则它将显示该帐户的分支和部门中的所有库存。如果省略@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

请注意,由于WHERE [Container].[Branch] = @Branch OR [Container].[Branch] = NULL,我无法使用LEFT JOIN方法;它返回预期记录的六倍。

2 个答案:

答案 0 :(得分:2)

此问题的典型模式是使用IsNull运算符,如下所示:

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

如果通过,它将与参数进行比较;否则,它会将列与自身进行比较。

答案 1 :(得分:0)

@bassrek是对的,你可以比较自己,你可以在JOIN条件中创建一个case表达式,并使你真正想要的任何值。还有一点需要注意的是,如果你的查询中唯一改变的是订单,为什么不在你的订单中写一系列的案例陈述来做你想要的排序而不是复制相同的查询3次然后改变订购。如果需要进行更改,它将使维护业务逻辑变得更容易。

另一种方法,而不是必须比较自己而不是性能,因为Sean建议可以使用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