【问题标题】:Stored Procedure trying to convert varchar to int for unknown reason存储过程尝试将 varchar 转换为 int 原因不明
【发布时间】:2015-11-10 06:08:17
【问题描述】:

我正在使用 SQL 参数来允许用户使用视图中的下拉菜单创建自己的 SELECT 查询。参数值使用 MVC 控制器中的实体框架从视图传递到存储过程。

我试图避免使用动态 SQL,所以我有几个选项可以做到这一点。

这是我最终选择的方法:

    @topLeftInput varchar(100),
    @topRightInput varchar(100)
AS
BEGIN
        Select  * from test
            where 
                CASE @topLeftInput 
                    WHEN 'BasicReturnReasonId' THEN BasicReturnReasonId
                    WHEN 'ClientName' THEN ClientName
                    WHEN 'CreditDeniedReasonId' THEN CreditDeniedReasonId
                    WHEN 'ItemsnotReturnedReasonId' THEN ItemsnotReturnedReasonId
                    WHEN 'ManufacturerId' THEN ManufacturerId
                    WHEN 'ManufacturerOrderNumber' THEN ManufacturerOrderNumber
                    WHEN 'ProductConditionId' THEN ProductConditionId
                                ELSE NULL
                    END
                = @topRightInput;
END

@topLeftInputClientNameManufacturerOrderNumber 时发生异常。当@topLeftInput 等于其中任何一个时,用户可以在文本框中输入@topRightInput 的值,而不是使用下拉菜单。

我收到一个异常,提示将 varchar 值转换为 int 时出错。不知道它为什么要这样做。

在我之前使用的技术中,这个异常并没有发生,它工作得很好(只是第一个选项的一个例子):

if @topLeftInput = 'BasicReturnReasonId'
    Begin
        Select * from test
            where BasicReturnReasonId = @topRightInput;
    End

为什么将这个 if 语句方法更改为 CASE 会导致这种异常?

【问题讨论】:

    标签: sql sql-server asp.net-mvc sql-server-2008 stored-procedures


    【解决方案1】:

    问题是case语句

    从类型集中返回最高优先级的类型 result_expressions 和可选的 else_result_expression

    尝试像这样更改您的查询

    Select  * 
    from test
    where 
    (@topLeftInput = 'BasicReturnReasonId' and BasicReturnReasonId = @topRightInput)
    or
    (@topLeftInput = 'ClientName' and ClientName = @topRightInput)
    or
    (@topLeftInput = 'CreditDeniedReasonId' and CreditDeniedReasonId = @topRightInput)
    or
    (@topLeftInput = 'ItemsnotReturnedReasonId' and ItemsnotReturnedReasonId = @topRightInput)
    or 
    ..
    

    或者您必须将integer 列显式转换为varchar 以避免隐式转换错误

    CASE @topLeftInput 
                        WHEN 'BasicReturnReasonId' THEN cast(BasicReturnReasonId as varchar(50))
                        WHEN 'ClientName' THEN ClientName
                        WHEN 'CreditDeniedReasonId' THEN cast(CreditDeniedReasonId as varchar(50))
                        WHEN 'ItemsnotReturnedReasonId' THEN cast(ItemsnotReturnedReasonId as varchar(50))
                        WHEN 'ManufacturerId' THEN cast(ManufacturerId as varchar(50))
                        WHEN 'ManufacturerOrderNumber' THEN cast(ManufacturerOrderNumber as varchar(50))
                        WHEN 'ProductConditionId' THEN cast(ProductConditionId as varchar(50))
                                    ELSE NULL
                        END
    

    【讨论】:

    • 有趣的是,我只使用第二种方法。我仍然收到第一个转换错误。
    【解决方案2】:

    case 表达式的值只能解析为一种类型。在某些情况下它不能返回integer,在其他情况下不能返回varchar。当您在可能的返回值中有混合类型时,SQL Server 会选择具有最高 precedence 的类型。在您的案例陈述中,它是int

    您必须确保所有可能的返回值都可以转换为最高优先级的类型。

    【讨论】:

    • 啊,我没有意识到这一点。所以如果我把它分成两个CASE 语句,这应该可以工作
    • 是的,两个 case 语句检查由 OR 分隔的等价性应该这样做。或者您可以在 case 语句中将所有值转换为 varchar。
    【解决方案3】:

    case 表达式根据where 子句的类型优先规则准确返回编译代码时确定的一种类型。

    换句话说,你不能用case 做你想做的事。只需使用单独的条件:

    where (@topLeftInput = 'BasicReturnReasonId' AND @topRightInput = BasicReturnReasonId) or
          (@topLeftInput = 'ClientName' AND @topRightInput = ClientName) or
          . . .
    

    出于性能原因(特别是如果您有索引),动态 SQL 是更好的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 2018-03-02
      • 2013-02-28
      • 1970-01-01
      相关资源
      最近更新 更多