我一直在玩T-SQL试图理解隐式转换和重载解析规则,但不知何故它似乎有点奇怪......
背景:
基本上后者告诉你abs
将对int,float,decimal等起作用。那么让我们看看它是如何工作的:
declare @foo2 sql_variant;
set @foo2 = abs(4);
select sql_variant_property(@foo2, 'BaseType')
-- result: int. OK, apparently we have an int overload. As expected.
declare @foo2 sql_variant;
set @foo2 = abs(cast(4.0 as float));
select sql_variant_property(@foo2, 'BaseType')
-- result: float. OK, apparently we have a float overload. As expected.
现在,根据隐式类型转换表,我们可以隐式转换内容。我们将通过将varbinary转换为int来检查这一点,这应该根据类型优先规则进行:
declare @foo varbinary(4);
set @foo = cast(4 as varbinary(4));
select @foo + 2;
-- result: int. OK, as expected.
从这个结果我希望以下内容也能正常工作:
declare @foo varbinary(4);
set @foo = cast(4 as varbinary(4));
select abs(@foo);
-- result: error: Operand type clash: varbinary is incompatible with float
东西我在这里不明白(问题):
答案 0 :(得分:1)
来自MSDN for Abs:
Arguments
numeric_expression
Is an expression of the exact numeric or approximate numeric data type category.
我猜调用Abs(varbinary)会尝试将varbinary转换为精确数字或近似数值数据类型。
Float位于这些类型的数据类型优先级的顶部,所以我猜是有问题。
用我的逻辑更新
declare @foo varbinary(4);
声明一个varbinary变量。
set @foo = cast( 4 as varbinary(4));
通过执行从int到varbinary的显式转换来设置此变量值,这是完全可行的。
select sql_variant_property(@foo, 'BaseType')
这表明该变量的类型为varbinary。
select abs(@foo);
尝试在varbinary上运行abs。 错误消息很明确:
Operand type clash: varbinary is incompatible with float
所以我的猜测是abs试图将varbinary隐式转换为数据类型优先级中的第一个,用于精确数字或近似数值数据类型,即float。
根据CAST and CONVERT
图表,此转化失败。
答案 1 :(得分:0)
我希望我做对了!评论赞赏。
您已经找到了MSDN页面的转换和优先级,所以让我们将您的示例分开。
declare @foo varbinary(4);
set @foo = cast(4 as varbinary(4));
现在,foo是什么类型的?
SELECT SQL_VARIANT_PROPERTY(@foo,'BaseType')
--------
varbinary
到目前为止这么好。但是@foo中有什么?
SELECT @foo
----------
0x00000004
现在,ABS()
接受numeric
- 浮点数:
与4.00
相比,4
看起来像什么?我们试试吧:
SELECT CONVERT(VARBINARY(MAX), 4.00) ,CONVERT(VARBINARY(MAX), 4);
------------------ -----------------------
0x0302000190010000 0x00000004
请参阅4.00
的内部表示与4
不同?它存储精度,比例和值,而你的'var in varbinary'不是。
这就是转换失败的原因。 ABS()
接受numeric
,您的'错误格式'varbinary
无法强制转换为numeric
,因为它不是一个,它是其他代表 - 我们知道它代表一个int但是SQL Server没有。
如果要将一个浮点数添加到varbinary的“内部”的int中,则必须执行类似
的操作select CONVERT(INT, @foo) + 2.0
回到你的例子:
declare @foo varbinary(max);
set @foo = cast(4.00 as varbinary(max));
SELECT ABS(@foo+2.0)
----------
6.0
4.00
以正确的内部格式转换为varbinary
,并通过numeric
电话愉快地强制转换为ABS()
。快乐的日子。