【问题标题】:Conditional Operator in SQL Where ClauseSQL Where 子句中的条件运算符
【发布时间】:2010-04-02 19:37:04
【问题描述】:

我希望我可以在 SQl Server 2005 中为我的 where 子句执行以下操作(我知道这是无效的)。有时@teamID(传递到存储过程)将是现有 teamID 的值,否则它将始终为零,我想要 Team 表中的所有行。

我使用 Case 进行了研究,并且运算符需要在整个语句之前或之后出现,这会阻止我根据 @teamid 的值使用不同的运算符。除了复制我的选择语句之外的任何建议。

    declare @teamid int
    set @teamid = 0

    Select Team.teamID From Team
      case @teamid
         when 0 then 
            WHERE Team.teamID > 0
         else
            WHERE Team.teamID = @teamid
      end 

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql


    【解决方案1】:

    你可以在没有案例的情况下做到这一点:

    SELECT  Team.teamID 
    FROM    Team
    WHERE   (@teamid = 0 AND Team.teamID > 0)
            OR (@teamid <> 0 AND Team.teamID = @teamid)
    

    【讨论】:

      【解决方案2】:

      不使用动态 SQL,性能最高的选项是:

      IF @teamid = 0
        BEGIN
      
          SELECT t.teamid
            FROM TEAM t
           WHERE t.teamid > 0
      
        END
      ELSE
        BEGIN
      
          SELECT t.teamid
            FROM TEAM t
           WHERE t.teamid = @teamid
      
        END
      

      使用动态 SQL:

      DECLARE @SQL NVARCHAR(4000)
         SET @SQL = 'SELECT t.teamid
                       FROM TEAM t
                      WHERE 1 = 1 '
      
         SET @SQL = @SQL + CASE @teamid
                             WHEN 0 THEN ' AND t.teamid > 0 '
                             ELSE ' AND t.teamid = @teamid '
                           END
      
      BEGIN
      
        EXEC sp_EXECUTESQL @SQL N'@teamid INT', @teamid
      
      END
      

      注意sp_EXECUTESQL 会缓存查询计划,而 EXEC 不会。阅读:http://www.sommarskog.se/dynamic_sql.html

      【讨论】:

      • 不会认为动态 SQL 或两个 IF 块增加的复杂性是值得的,除非您正在查询中国国家体育协会数据库;-)
      • 但是性能提升是否值得复杂性和维护成本损失?
      • 这三个选项各有利弊 - 错过了 Andomar 建议中的括号,事情将无法按预期进行。
      【解决方案3】:

      怎么样:

      Select Team.teamID From Team Where (@teamid=0 and team.teamID>0) or (@teamid<>0 and team.teamid=@teamid)
      

      【讨论】:

        【解决方案4】:

        甚至比 Andomar 的答案更简单,并且假设 id 永远不会是 0(对于大多数自动增量 id)是

        SELECT  Team.teamID 
        FROM    Team
        WHERE   @teamid = 0 or Team.teamID = @teamid;
        

        当@teamid 为零时,该谓词始终为真,否则仅当它与特定行的teamId 匹配时才为真。

        但是请注意:这在 Sybase 11 或更高版本上非常有效;它在 MS SQL server 2003 上的工作效率很低;我不知道它在当前版本的 MS SQL Server 上是如何工作的。

        另外,你可以用例;您只需要将 case 放在 where 子句中,而不是 case 中的 where 子句中。所以你原来的查询是:

        Select Team.teamID 
        From Team
        where 
           case when @teamid = 0 then 0 else Team.teamID end = @teamId;
        

        但请注意,这可能会降低效率,因为它必须按行进行评估,并且还可能导致全表扫描。

        我上面给出的表格更有可能被智能查询优化器重写(您的里程取决于您的 RDBMS)以在@teamid 不为零时使用索引。

        【讨论】:

        • +1 你的第一个答案太棒了。更简单的可能是@teamid in (0, TeamID)
        • 谢谢!但是使用 inlist 可能不会导致优化。
        • in 列表只是语法糖。我认为 a in (b,c) 在优化器看到之前扩展为 a=b or a=c
        【解决方案5】:

        如果您可以将 Null 视为所有记录:

        WHERE Team.teamID = ISNULL(@teamid, Team.teamID)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-06-15
          • 1970-01-01
          • 1970-01-01
          • 2017-11-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多