CASE THEN clause always evaluated

≯℡__Kan透↙ 提交于 2019-12-06 02:09:21

问题


I'm doing a SELECT which uses CASE to convert nvarchar values into a proper type, something like this:

SELECT CASE 
    WHEN @propType = 'money' THEN convert(money, datavalue)
    [...]
    ELSE datavalue
END
FROM [...]

However, it seems the convert is always executed, even when @propType is not equal to money. Runnable example:

declare @proptype nvarchar(50)= 'nvarchar'
declare @val nvarchar(10) = 'test'
select 
    case @proptype
        when 'money' then convert(money, @val)
        else @val
    end

Why is this, and how can I get around it? The MSDN documentation says this:

The CASE statement evaluates its conditions sequentially and stops with the first condition whose condition is satisfied. In some situations, an expression is evaluated before a CASE statement receives the results of the expression as its input. Errors in evaluating these expressions are possible. Aggregate expressions that appear in WHEN arguments to a CASE statement are evaluated first, then provided to the CASE statement. For example, the following query produces a divide by zero error when producing the value of the MAX aggregate. This occurs prior to evaluating the CASE expression.

I'm not sure this is relevant, but the language is somewhat heavy for a non-native, so maybe it is?


回答1:


Have a look at the following Use caution when Using CONVERT() with CASE or IF functions in Transact SQL (T-SQL)

The first thoughts are generally one of the following "Since the first value evaluated is numeric, it is converted to decimal, and all other data is expected to be a decimal as well" OR "If SQL Server is able to convert ANY of the values to the specified type, then all values are expected to be of the converted type". However, that's not correct (although the second is close)!

The real problem is that if you choose to Convert the values anywhere within the Case statement, the datatype you are converting the values to is the expected type of ALL the values regardless of if they are of that type or not. Further, even if NONE of the values can actually be converted (even if the Convert line of code never executes), ALL of the values are still expected to be of the type specified by the Convert function!




回答2:


To be clear about what is happening the then clause is not being evaluated.

You see the same error if you do

SELECT CASE @proptype
         WHEN 'money' THEN $1.0 /*<-- Literal of datatype money*/
         ELSE @val
       END 

The documentation for CASE explains that the Return Type

Returns the highest precedence type from the set of types in result_expressions and the optional else_result_expression. For more information, see Data Type Precedence (Transact-SQL).

money has higher datatype precedence than nvarchar so the else @val is evaluated then that gets cast to money and fails.

One possible workaround would be to cast it to sql_variant as this has higher data precedence than both.

declare @proptype nvarchar(50)= 'nvarchar'
declare @val nvarchar(10) = 'test'
select 
    case @proptype
        when 'money' then convert(money, @val)
        else cast(@val as SQL_VARIANT)
    end


来源:https://stackoverflow.com/questions/11898427/case-then-clause-always-evaluated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!