【问题标题】:Where clause with three options带有三个选项的 Where 子句
【发布时间】:2018-04-20 00:56:49
【问题描述】:

我正在使用 SQL Server 2016 Dev,并且我有一个带有 3 个选项的 WHERE 子句。

我解决了 2,我需要帮助解决第三个问题。请看代码。

我不能使用 CTE 或任何其他代码,因为它是遗留代码的一部分,除了 where 子句中的情况外,不能修改。

要求

When DepartmentID = 99 then all records
When DepartmentID = 97 then only PriorityID 10 records
All other Departments = all records except PriorityID 10

样本数据

Create table Department
(
    DepartmentID int null,
    PriorityID   int null
)
GO

Insert into Department (DepartmentID, PriorityID) 
values (1, 2), (2, 2), (3, 10), (4, 3), (5, 4), 
       (97, 10), (99, 10), (4, 5), (5, 3), (2, 10),
       (99, 2), (97, 1), (3, 2), (3, 3), (2, 5)
GO

Select * from Department

到目前为止我的查询

--Declare @intDepartmentID int = 99 OK
--Declare @intDepartmentID int = 97 OK
Declare @intDepartmentID int = 2 -- Need to exclude Record with PriorityID = 10
Declare @intPriorityID int = null

IF @intDepartmentID = 99
Begin
    Set @intDepartmentID = null
    Set @intPriorityID = null
End

If @intDepartmentID = 97
Begin 
    Set @intDepartmentID = null
    Set @intPriorityID = 10
End

Select DepartmentID,
        PriorityID
From Department
Where (DepartmentID = @intDepartmentID or @intDepartmentID is null)
    -- I think I need case statement here?
And (PriorityID = @intPriorityID or @intPriorityID is null)

【问题讨论】:

  • 您的预期结果是什么?
  • 有人给你投了反对票,因为你在代码的注释部分留下了要求。我想我的回答会做你喜欢的,但你还是可以考虑编辑这个问题。

标签: sql sql-server case sql-server-2016


【解决方案1】:

请检查此查询。

SELECT DepartmentID,
        PriorityID
FROM Department
WHERE ((PriorityID != (CASE  
                WHEN (@intDepartmentID NOT IN (97, 99)) THEN 10
                END) AND @intDepartmentID NOT IN (97,99))
OR (PriorityID = (CASE  
WHEN @intDepartmentID = 99 THEN PriorityID
WHEN @intDepartmentID = 97 THEN 10
END) AND @intDepartmentID IN (97,99))
)
--AND (DepartmentID = @intDepartmentID OR @intDepartmentID is null)  --If you want to filter data by department then enable this condition

【讨论】:

  • 感谢您的快速响应,但不适用于 99 或 97
  • 如果您在每种情况下都提供了您想要的结果,那就太好了。
【解决方案2】:

首先,您不需要将@intPriorityID 作为参数之一,因为PriorityID 值由@intDepartmentID 确定。

请试试这个,如果这是您需要的,请告诉我:

SELECT DepartmentID,
        PriorityID
FROM Department
WHERE (1 =
    (CASE WHEN @intDepartmentID = 99 THEN 1 END)
    OR
    PriorityID = 
    (CASE WHEN @intDepartmentID = 97 THEN 10 END)
    OR
    PriorityID <> 
    (CASE WHEN @intDepartmentID NOT IN (99,97) THEN 10 END)
    )

【讨论】:

    【解决方案3】:

    真的应该在您的问题中包括您对每个参数值的预期结果。

    根据您对其他答案的 cmets,我认为您确实希望按 DepartmentID 过滤,而不管 @intDepartmentID 参数的值如何,并使用一些额外的逻辑来确定您是否也希望按 PriorityID 过滤.

    这是一种方法。

    SELECT * 
    FROM @Department AS D
    WHERE
        (D.DepartmentID = @intDepartmentID)
        AND
        (
            (@intDepartmentID = 99)
            OR
            (@intDepartmentID = 97 AND D.PriorityID = 10)
            OR
            (@intDepartmentID NOT IN (97, 99) AND D.PriorityID <> 10)
        )
    OPTION(RECOMPILE);
    

    上面编写比较的简单方法假设DepartmentIDPriorityID@intDepartmentID 不能是NULL。 如果它们可以NULL,正如您在示例数据中的CREATE TABLE 语句所暗示的,那么请在示例数据中添加一些带有NULL 的相关行以说明您数据中的所有情况。此外,请确保在问题中包含预期结果。

    这种查询容易出现参数嗅探问题,所以我加了OPTION(RECOMPILE)。如果您不这样做,此查询的性能可能取决于您第一次运行它时使用的参数值。

    【讨论】:

    • 弗拉基米尔,谢谢你的回复,这就是我需要的如何将这三个结合起来
    【解决方案4】:

    如果我理解了这个问题:

    1) 使用@intDepartmentID = 99,您希望所有记录都没有过滤器。
    2) 使用@intDepartmentID = 97,您希望所有使用PriorityID = 10 的记录
    3) 使用@intDepartmentID NOT IN (97, 99),您需要指定DepartmentID 但使用PriorityID &lt;&gt; 10的所有记录

    根据您的测试数据,这意味着:

    DepID   PriID   Visible if:
    1       2       @intDepartmentID = 99,  @intDepartmentID = 1
    2       2       @intDepartmentID = 99,  @intDepartmentID = 2
    3       10      @intDepartmentID = 99,  @intDepartmentID = 3,  @intDepartmentID = 97
    4       3       @intDepartmentID = 99,  @intDepartmentID = 4
    5       4       @intDepartmentID = 99,  @intDepartmentID = 5
    97      10      @intDepartmentID = 99,  @intDepartmentID = 97
    99      10      @intDepartmentID = 99,  @intDepartmentID = 97
    4       5       @intDepartmentID = 99,  @intDepartmentID = 4
    5       3       @intDepartmentID = 99,  @intDepartmentID = 5
    2       10      @intDepartmentID = 99,  @intDepartmentID = 2,  @intDepartmentID = 97
    99      2       @intDepartmentID = 99  
    97      1       @intDepartmentID = 99  
    3       2       @intDepartmentID = 99,  @intDepartmentID = 3
    3       3       @intDepartmentID = 99,  @intDepartmentID = 3
    2       5       @intDepartmentID = 99,  @intDepartmentID = 2
    

    这是查询:

    Select * 
    from Department
    where 
        case @intDepartmentID 
            when 99 then 1 
            when 97 then 
                case when (PriorityID = 10) then 1 else 0 end
        else
            case when ((@intDepartmentID = DepartmentID) and (PriorityID <> 10)) then 1 
            else 0 end
        end = 1
    

    【讨论】:

      【解决方案5】:
      where DepartmemtID = @DepartmentID and
          <add one of the two case expressions below>
      
          case @DepartmentID
             when 99 then 1
             when 97 then case when PriorityID = 10 then 1 end
             else case when PriorityID <> 10 then 1 end
          end = 1
      
      -- or
      
          case 
             when @DepartmentID = 99 then 1
             when @DepartmentID = 97 and PriorityID  = 10 then 1
             when @DepartmentID = 97 then 0 -- all other priorities
             when PriorityID <> 10 then 1
          end = 1
      

      第二个嵌套较少,正如所写,它确实有点依赖于早期案例的失败。此外,如果您有空值,您也需要对此进行调整。

      一般的想法是使用case 仅针对您感兴趣的条件返回匹配值(在此示例中为 1)。随着这些条件变得更加复杂,能够浓缩逻辑会很好通过依赖早期的案例是错误的,我认为它通常也更容易维护。请记住,顺序很重要。

      【讨论】:

      • 感谢您的快速响应,但不适用于 DepartmentID 2 它应该显示 2 条记录
      • @OdedDror 好的,我看到你仍然想要平等检查。
      【解决方案6】:

      终于按预期工作了

      Where 
      ( 
          PriorityID = (CASE @intDepartmentID WHEN 99 then PriorityID  WHEN 97 then 10 END )
          OR  (PriorityID != case when @intDepartmentID not in (99,97) then 10 end )
          and (DepartmentID = @intDepartmentID )
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-12
        • 2011-07-05
        • 1970-01-01
        • 2011-07-23
        相关资源
        最近更新 更多