每天进步一点点:MS-SQL保留指定位数小数

春节期间是娱乐的时间,不过如果整天娱乐不学习浑身都难受,所以偶尔还是要调剂一下,娱乐之余就要学习。

每天进步一点点
image.png
(图源 :pixabay)

话说,前段时间在研究使用HiveSQL查询历史挂单以及成交,发现计算出来的价格小数点后有很多位数字,这让生成的表格看起来不是那么规整。

那么有没有什么办法,让数字看起来更规整一些呢?其实从应用的角度看,我们大可以不用关心这点,因为SQL返回的数据一般都要再次进行处理的。

比如说,在Python中,我们就可以通过round()或者格式化输出,来实现我们想要的功能,相应代码如下:

使用round()

a = 1.1118
b = round(a, 3)
print(b)

使用格式化输出:

a = 1.1118
print(f'{a:.3f}')

其它语言中也都有类似的机制,就不再赘述了。

现在的问题是,如何使用SQL(SQL Server)来达成我们的目标,而不是使用第三方语言再对数据进行额外处理。

首先,尝试使用round函数,为了便于说明问题,我们直接取一个包含N多位小数的数字,而不是直接从数据库中查询中计算出来的小数。

执行如下查询:

select round(0.3694826767916468913, 3);

结果如下:

image.png

咦,这个结果是什么鬼?把0.3694826767916468913变成了0.3690000000000000000,看起来更不舒服了。

看了一下微软官网上关于round函数的介绍,其中返回值部分是这样说的:

image.png

也就是说,根据输入的数据来判断输出的类型,所以对于一个小数点后有N位小数的数字而言,它返回的数字也是包含N位小数,也就是说在[SQL Server] SQL中,round只负责四舍五入,不负责截短,这和我想要的不一致呀?

如果我们使用的MySQL,那么应该可以用类似如下语句来负责截短:

SELECT TRUNCATE(135.376, 2);

然而无论是文档以及实测,都表明MS SQL是不支持TRUNCATE函数的,所以得另想办法。

这时候就得请出CAST函数了,其语法如下:

CAST ( expression AS data_type [ ( length ) ] )

也就是说,可以表达式转换成我们需要的数据类型,回到我们的例子中,我们就可以使用如下语句来处理我们的数据:

SELECT CAST (0.3694826767916468913 AS decimal (18,3));

关于decimal数据类型,表示为decimal[ (p[ ,s] )],其实就是我们常用的十进制数,详情可以参考这里:decimal and numeric (Transact-SQL)

其中p (精度),代表要存储的十进制数字的最大总数,默认为18;s(比例),代表存储在小数点右侧的小数位数。

上述查询返回如下结果:

image.png

这是我们想要的结果,所以之前文章中的那个SQL就可以修改为:

select top 200 current_pays, current_pays_symbol, open_owner, open_pays, open_pays_symbol, 
    CAST(current_pays/open_pays AS decimal (18,3))as price, timestamp
    from VOFillOrders 
    where current_owner='oflyhigh' 
    order by timestamp desc

也就是说,将之前SQL中的:

amount_to_sell/min_to_receive as price
修改为:
CAST(current_pays/open_pays AS decimal (18,3))as price

对比下输出,修改之前:

image.png

修改之后:

image.png

很明显,后者舒服多啦,更方便我们阅读和分析。

相关链接

Sort:  

好好学习 天天向上

学霸都是这样的,走到哪学到哪。

仔细看了很久,除了看不懂之外就剩下看不懂了。

真厉害,像你学习!

好勤快的O哥😁

如果能向O哥这么努力,估计我厦大就考上了😂