你有 3 代表 222.9375 那是因为REVERSE
接受一个字符串表达式。通过传入一个浮点数,SQL Server 必须进行从浮点数到 varchar 的隐式转换。
根据在线图书:
转换和转换 (Transact-SQL)
float 和 real 样式
当表达式为 float 或 real 时,style 可以是下表中显示的值之一。其他值被处理为 0。
值
0(默认)
输出
最多 6 位。适当时以科学记数法使用。
可以使用以下示例将上述定义可视化:
declare @a float = 222.9375, @b float = 12.34564, @c float = 1234564.123456
select convert(varchar, @a, 0) -- Returns 222.938 -- Notice only 6 digits are displayed
, convert(varchar, @b, 0) -- Returns 12.3456 -- Notice only 6 digits are displayed
, convert(varchar, @c, 0) -- Returns 1.23456e+006 -- Notice only 6 digits are displayed
如果您继续使用浮点数作为您的数据类型,那么即使您float
转换varchar
并执行字符串操作,您也不能期望得到您正在寻找的确切数字。
您甚至不能简单地float
转换decimal
,因为您不知道要分配给小数点的小数位数(比例)。
Alternatively, if you start with decimal as the data type, then you automatically know how many decimal places a number has because you had to declare it.
For example
declare @number decimal(19, 4) = 222.9375
select @number -- 222.9375
Let's take it one step further. To work out the scale (number of decimal places) after some sort of calculation, you can employ the function below to get the answer:
declare @newnumber decimal(19, 4) = 222.9375
select @newnumber * @newnumber -- Returns 49701.1289063
, sql_variant_property(@newnumber * @newnumber, 'scale') -- Returns 7
However, you will most likely have no control over the data type used, one way I can think of is by combining the usage of both decimal
and varchar
to achieve what you want.
declare @newnumber float = 222.9375
-- The first 6 columns are just the working steps, solution is in the last column.
select
@newnumber as 'original'
, cast(@newnumber as decimal(38, 18)) as 'decimal' -- Assuming all your numbers can fit in decimal(38, 18).
, cast(cast(@newnumber as decimal(38, 18)) as varchar(max)) as 'varchar'
, reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as 'reverse'
, cast(reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as decimal(38, 0)) as 'decimal'
, len(cast(reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as decimal(38, 0))) as 'len'
, case charindex('.', @newnumber)
when 0 then 0
else len(cast(reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as decimal(38, 0)))
end as 'All In One Step'