IN子句中的SQL逗号分隔值case语句错误

时间:2013-05-01 07:36:31

标签: sql sql-server

我在下面的项目上遇到错误,我不明白为什么。任何人都能为我解释一下吗?

CREATE FUNCTION dbo.fn_AcMonthOrder
(
    @Month varchar(100)
)
RETURNS INT 
AS
BEGIN 
    DECLARE @MonthOrder Int 
    SET @MonthOrder = 
        (CASE 
        WHEN @Month IN ('Aug','August',8) THEN 1 
        WHEN @Month IN ('Sep','September',9) THEN 2 
        WHEN@Month IN ('Oct','October',10) THEN 3 
        ...
        ELSE 0 END)
    RETURN @MonthOrder
END 

如果我尝试调用此函数,那么它适用于整数,但不适用于varchars。即PRINT @ dbo.fn_AcMonthOrder(8)将按预期返回1,但PRINT @ dbo.fn_AcMonthOrder('Aug')或PRINT @ dbo.fn_AcMonthOrder('August')将返回以下错误:

Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'Aug' to data type int.

4 个答案:

答案 0 :(得分:2)

在表达式中使用不同的数据类型时,SQL Server会跟随data type precedence。在这种情况下:

8 IN ('Aug','August', 8) 

您正在将intvarchar混合。由于int具有更高的优先级,因此会将varchar转换为int。这种特殊情况不会引发错误的原因可能是优化。这确实会引发错误:

8 IN ('Aug','August',10) 

这不会引发错误:

'Aug' IN ('Aug','August',8) 

但这会再次引发错误:

'Sept' IN ('Aug','August',8) 

这确认优化器首先比较不需要转换的元素。它只会在遇到无法转换的元素时引发错误。

在一天结束时,最好的解决方案是确保所有数据类型都相同。在您的情况下,您可以将数字列为字符串:

WHEN @Month IN ('Aug','August','8') THEN 1 
                              ^^^^^

答案 1 :(得分:1)

        WHEN @Month IN ('Aug','August','8') THEN 1 
        WHEN @Month IN ('Sep','September','9') THEN 2 
        WHEN@Month IN ('Oct','October','10') THEN 3 

将单引号月份值包含在数字中,例如将8更改为“8”。 这是因为@Month属于VARCHAR()数据类型,IN()子句要求其中的值必须在它们之间具有兼容的数据类型转换。

答案 2 :(得分:1)

IN列表中的所有元素都必须是可以进行隐式转换的类型。您无法将varchar值转换为整数值,反之亦然。所以试试这个陈述。

CREATE FUNCTION dbo.fn_AcMonthOrder
(
  @Month varchar(100)
)
RETURNS INT AS
BEGIN
  DECLARE @MonthOrder Int
  SET @MonthOrder =
    (CASE
      WHEN @Month IN ('Aug','August','8') THEN 1
      WHEN @Month IN ('Sep','September','9') THEN 2
      WHEN@Month IN ('Oct','October','10') THEN 3
      ELSE 0
    END)
  RETURN @MonthOrder
END

答案 3 :(得分:1)

当你使用IN子句时,你应该使用一个DataType,现在你使用'Aug' 8 附近,它假定它应该转换'aug',... 。到int它是不正确的。 你可以用这种方式写出来(为你们所有人做这件事)

WHEN @Month IN ('Aug','August','8') THEN 1 
.....