我最近在TSQL中将CASE
语句更改为ISNULL
函数时遇到了一个有趣的问题。我正在使用的查询用于获取我工作的网站的一些用户属性和权限。以前,该查询有许多类似于以下内容的CASE
语句:
注意:示例中的a.column1
在表中的类型为bit
。另请注意,[CanDoSomething]
结果列有时用作网站中的字符串。
SELECT
...
CASE
WHEN a.column1 IS NULL THEN 0
ELSE a.column1
END [CanDoSomething]
...
FROM
a
DBA用CASE
函数替换了这些ISNULL
语句:
SELECT
...
ISNULL(a.column1, 0) [CanDoSomething]
...
FROM
a
这似乎是一个很好的改变,但是在C#中检索数据时会出现意外情况。使用上一个查询,从C#中的[CanDoSomething]
访问时DataTable
列的值为1
或0
。当我们更改为使用ISNULL
时,C#中的值随后更改为true
或false
,当被视为字符串时,显然与1
或0
。
这引起的错误已经得到解决。我只是好奇为什么ISNULL
返回的值不同于同等的CASE
语句,我似乎无法在Google上找到任何答案。
答案 0 :(得分:5)
答案是documentation of ISNULL
's return type:
ISNULL ( check_expression , replacement_value )
返回与
check_expression
相同的类型。如果文字NULL
作为check_expression
提供,则返回replacement_value的数据类型。如果提供的文字NULL
为check_expression
且未提供replacement_value
,则返回int
。
与CASE
表达式不同,始终返回 * 返回int
int
,因为第一个分支中为零, ISNULL
将返回其第一个参数类型的值,即a.column1
。
<小时/> * 编辑前
CASE
表达式为WHEN a.column1 IS NULL THEN 0 ELSE 1
。
答案 1 :(得分:5)
扩展@ dasblinkenlight的解释:
真正的问题是,每the documentation,case
个表达式
从中输入类型集中的最高优先级类型 * result_expressions *和可选的* else_result_expression *。 有关详细信息,请参阅Data Type Precedence (Transact-SQL)。
isnull()
返回与* check_expression *
相同的类型
在您的情况下,这是bit
。您的case
表达式:
CASE
WHEN a.column1 IS NULL THEN 0
ELSE a.column1
END
具有返回两种不同数据类型的执行路径,int
(文字值0
)和bit
(列的值)。如果您查看上面链接的data type precedence chart,则int
的优先级高于bit
,因此bit
值会转换为int
。
这是因为从bit
到int
的转换是扩展转换。 Sql Server的bit
类型本质上是1位整数值,因此没有数据丢失。从int
到bit
的转换是缩小转化,并且存在数据丢失的可能性(至少在概念上)。
如果DBA使用了coalesce()
而不是isnull()
,这本来是我个人的选择,你不会遇到这个问题,因为coalesce()
被定义为返回一个类型类似于case
。 coalesce()
返回具有最高数据类型优先级的表达式的数据类型。如果所有表达式都是不可为空的,则结果将被输入为nonnullable。