【问题标题】:T-SQL 'AND' keyword not short-circuiting it seemsT-SQL 'AND' 关键字似乎没有短路
【发布时间】:2012-05-19 13:22:39
【问题描述】:

下面的存储过程工作正常,除了当我在“where”子句中取消注释日期检查的第二部分时,即使传入的关键字为空或“111”,它也会在日期转换时爆炸。

我愿意接受有关如何以不同方式执行此动态 where 子句的任何建议。

感谢您的帮助。

 ALTER PROCEDURE [SurveyEngine].[GetPageOf_CommentsOverviewRowModel]
        @sortColumn varchar(50),
        @isASC bit,
        @keyword varchar(50)
    AS
    BEGIN

        declare @keywordType varchar(4)
        set @keywordType = null

        if ISDATE(@keyword) = 1
            set @keywordType = 'date'
        else if ISNUMERIC(@keyword) = 1
            set @keywordType = 'int'

        select      c.CommentBatch BatchID, c.CreatedDate DateReturned, COUNT(c.CommentID) TotalComments
        from        SurveyEngine.Comment c 
        where       (@keywordType is null)
        or          (@keywordType = 'date') --and c.CreatedDate = @keyword)
        or          (@keywordType = 'int' and (CONVERT(varchar(10), c.CommentBatch) like  @keyword+'%'))

        group by    c.CommentBatch, c.CreatedDate
        order by    case when @sortColumn = 'BatchID' and @isASC = 0 then c.CommentBatch end desc,
                    case when @sortColumn = 'BatchID' and @isASC = 1 then c.CommentBatch end,
                    case when @sortColumn = 'DateReturned' and @isASC = 0 then c.CreatedDate end desc,
                    case when @sortColumn = 'DateReturned' and @isASC = 1 then c.CreatedDate end,
                    case when @sortColumn = 'TotalComments' and @isASC = 0 then COUNT(c.CommentID) end desc,
                    case when @sortColumn = 'TotalComments' and @isASC = 1 then COUNT(c.CommentID) end
    END

【问题讨论】:

  • 我在发布之前检查了那个,但我真正的问题是为什么当@keywordType 不是“日期”时,'and' 运算符不会阻止第二个语句被评估。一定有一些非常明显的东西,但我没有看到。
  • 假设 c.CraetedDate 是一个日期,那么可能是 (@keywordType = 'date' and c.CreatedDate = Convert(DateTime,@keyword)) ?
  • 我应该补充一点,如果你给它一个格式正确的日期,它就可以工作。所以,如果关键字 = '1/1/1999' 一切都很好。如果关键字 = 'zzz' 它会在日期转换时爆炸。
  • hmm Convert(VarChar(10),c.CreatedDate) = 关键字将删除隐式转换,但这意味着关键字必须具有特定格式,当它包含日期时。

标签: tsql


【解决方案1】:

根据这个人的博客:http://blogs.msdn.com/b/bartd/archive/2011/03/03/don-t-depend-on-expression-short-circuiting-in-t-sql-not-even-with-case.aspx 看起来你不能保证 where 子句中的操作顺序,即使支持短路。执行计划可能会选择先评估第二条语句。

他建议改用 case 结构(如前面提到的 pst),因为它“更多”得到保证。但我不认为我可以将你的 where 子句重写为 case,因为你使用了三个不同的运算符(为 null、= 和 LIKE)。

【讨论】:

    【解决方案2】:

    编辑对不起,脑云。事物需要以不同的方式初始化。

    将设置更改为:

        declare @keywordType varchar(4)
        declare @TargetDate as DateTime = NULL
    
        set @keywordType = null 
    
        if ISDATE(@keyword) = 1
            begin
            set @keywordType = 'date'
            set @TargetDate = Cast( @keyword as DateTime )
            end
        else if ISNUMERIC(@keyword) = 1 
            set @keywordType = 'int' 
    

    然后改变:

    and c.CreatedDate = @keyword
    

    到:

    and c.CreatedDate = Coalesce( @TargetDate, c.CreatedDate )
    

    如果您不按日期搜索,这将导致 NOP。

    【讨论】:

    • 这很有效,让我可以在工作中继续我的项目。也很高兴了解 Coalesce,它看起来非常有用。
    猜你喜欢
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    相关资源
    最近更新 更多