我在sql server中有这个简单的表:
DECLARE @tbl table( a int , b NVARCHAR(100), isCalcByA bit)
INSERT INTO @tbl
SELECT 1,'c',1
UNION ALL
SELECT 2,'d',0
确定。
如果我这样做:
SELECT CASE
WHEN isCalcByA = 1 THEN a
ELSE b
END FROM @tbl
产生错误:
Msg 245,Level 16,State 1,Line 9
将nvarchar值'd'转换为数据类型int时,转换失败。
我可以理解为什么会这样:
因为正在累积(要显示)的数据无法在同一列附加int
和string
。
确定
但是这个怎么样:
SELECT 'dummy'
FROM @tbl
WHERE CASE
WHEN isCalcByA = 1 THEN a
ELSE b
END IS NOT NULL
此处 -
string
not null
而不是string
或int
值进行检查。但我仍然遇到相同的错误。
我错过了什么?
NB
我知道我可以/应该这样做:
SELECT 'dummy'
FROM @tbl
WHERE
(isCalcByA = 1 AND a IS NOT NULL)
OR
(isCalcByA <> 1 AND b IS NOT NULL)
(工作正常)
但我问为什么它不适用于第一个CASE
情况
答案 0 :(得分:3)
CASE
是表达式 - 它返回特定类型的值。它可能返回的所有可能值都必须可以转换为某种常见类型。系统使用类型优先级规则来考虑所有可能返回值的类型,并确定该常见类型是什么。 int
具有更高的优先级并获胜。
CASE
WHEN isCalcByA = 1 THEN CONVERT(nvarchar(100),a)
ELSE b
END
会起作用,因为现在选择的常用类型是明确的nvarchar(100)
。
答案 1 :(得分:1)
无论您是在CASE
还是SELECT
子句中使用WHERE
。 CASE
表达式应始终返回相同的数据类型。因此,将两列都转换为可以同时包含两者的数据类型:
CASE
WHEN isCalcByA = 1 THEN CAST(a AS NVARCHAR(100))
ELSE b
END
来自CASE
expression文档:
从result_expressions中的类型集和可选的else_result_expression返回最高优先级类型。
当各种WHEN
和ELSE
部分具有不同的数据类型作为结果时,从该列表中选择最高优先级:Data Type Precedence并且所有结果都将转换为该数据类型。
您的查询失败,因为int
的优先级高于nvarchar
。
答案 2 :(得分:0)
DECLARE @tbl table( a int , b NVARCHAR(100), isCalcByA bit)
INSERT INTO @tbl
SELECT 1,'c',1
UNION ALL
SELECT 2,'d',0
UNION ALL
SELECT null,'d',1
SELECT CASE
WHEN isCalcByA = 1 THEN CAST(a AS VARCHAR(30))
ELSE b
END FROM @tbl
上面,您将根据选择选择两种不同的数据类型。
SELECT 'dummy'
FROM @tbl
WHERE CASE
WHEN isCalcByA = 1 THEN CAST(a AS VARCHAR(30))
ELSE b
END IS NOT NULL
以上,无论条件如何,您每次都选择'哑'。
因此,在第一个声明中,您要根据return type
设置case
,并且案例可以返回two different types
。在第二个查询中,返回类型始终为same type
。
答案 3 :(得分:0)
不要将CASE
视为内置IF
来自常规语言。它更像是具有强类型的... ? ... : ...
运算符 - 它必须导致特定的单数类型。如果要混合列,则需要将其转换为例如nvarchar。
你也可以考虑一下,因为SELECT的结果应该可以由CREATE TABLE
来定义。