在sql

时间:2016-10-04 10:56:58

标签: sql-server tsql case

我有一个查询,我必须使用case语句进行过滤。似乎每个案件的条件都在执行:

declare @filterValue varchar(50)='test'
    declare @filterCol varchar(50)='DayOfWeekAbr'

    select * from datetable where 1=1 and (
    case when @filterCol='' then DayOfWeekAbr
     when @filterCol='' then [WeekOfYear]
    end = @filterValue
    OR case when ISNULL(@filterCol,'')='' then 1
    end =1)

获取错误:

  

Msg 245,Level 16,State 1,Line 5   转换varchar值时转换失败' test'数据类型int。

现在错误是因为列WeekOfYear是int。但我怀疑的是案件情况是否与执行案件的情况不符?并解决方法如何做到。

当在下面的查询中实现时,得到相同的错误告诉我我错在哪里:

   SELECT
                [threat_feed].[Id]
              , [threat_feed].[Name]
              , [threat_feed].[Url]
              , [threat_feed].[RefreshRate]
              , [threat_feed].[ConfidenceLevel]
              , [threat_feed].[Severity]
              , [threat_feed].[Type]
              , [threat_feed].[Source]
              , [threat_feed].[Description]
              , [threat_feed].[Visibility]
              , [threat_feed].[Integration]
              , [threat_feed].[IntegrationOptions]
              , [threat_feed].[CreatedBy]
              , [threat_feed].[CreatedOn]
              , [threat_feed].[ModifiedBy]
              , [threat_feed].[ModifiedOn]
              , [threat_feed].[IsDeleted]
              , COUNT(*) OVER () AS [TOTALROWS]

            FROM    [dbo].[ThreatFeed] [threat_feed]
            WHERE   [threat_feed].[IsDeleted] IN (0, @IncludeDeleted) AND (
        (@filterCol = 'Name' and [threat_feed].[Name]  =  @filterValue) or
        (@filterCol = 'Source' and [threat_feed].[Source] = @filterValue) or
        (@filterCol = 'URL' and [threat_feed].[Url] = @filterValue) or
        (@filterCol = 'RefreshRate' and [threat_feed].[RefreshRate]  =  @filterValue) or
        (@filterCol = 'ConfidenceLevel' and [threat_feed].[ConfidenceLevel] = @filterValue) or
        (@filterCol = 'Severity' and [threat_feed].[Severity] = @filterValue) or
        (@filterCol = 'Visibility' and [threat_feed].[Visibility] = @filterValue) or
        (isnull(@filterCol,'')='')
        )

此处置信度,服务器和可见性不是varchar

1 个答案:

答案 0 :(得分:2)

问题可能是case中的where表达式。说实话,没有case就可以更简单地完成。我想这就是你想要的:

where ( (@filterCol = 'DayOfWeekAbr' and DayOfWeekAbr =  @filterValue) or
        (@filterCol = 'WeekOfYear' and WeekOfYear = @filterValue) or
        (@filterCol is null)
      )

编辑:

哦,这很有意思。 SQL(通常)不保证对布尔表达式进行惰性求值。因此,可能会评估or的两侧。 。 。当过滤器值是一个字符串时,这可能会导致问题,但该列需要一个数字。

这是一个解决方案:

where (case when @filterCol = 'Name' and [threat_feed].[Name] = @filterValue) then 1
            when @filterCol = 'Source' and [threat_feed].[Source] = @filterValue)
            then 1
            . . .
        end) = 1

然后,确保所有字符串列都在日期列之前。 case 中的条款保证按顺序搜索。

在SQL Server 2012+中,另一种可能性是将try_convert()用于非字符串列。是的,如果RefreshRate是一个整数:

where . . .
        (@filterCol = 'URL' and [threat_feed].[Url] = @filterValue) or
        (@filterCol = 'RefreshRate' and [threat_feed].[RefreshRate]  =  try_convert(int, @filterValue) ) or