SQL Server使用datediff计算时间差获取正确十进制小时值
问题描述
我正在SQL Server中使用datediff函数查询同一张表的两个datetime列,想要得到以小数形式呈现的小时时长结果。
我最初编写的查询语句如下:
Select startdatetime, enddatetime, datediff(minutes, startdatetime, enddatetime) / 60 as 'Hrs worked' from table1
得到的结果示例如下:
startdatetime | enddatetime | Hrs. worked 2019-02-28 06:00:00.0000000 -08:00 2019-02-28 07:15:00.0000000 -08:00 1
显然startdatetime和enddatetime的差值应为1.25而非1,请问有没有办法展示1.25这类十进制数值?
我也尝试了如下写法:
Select StartDateTime, EndDateTime, Convert(decimal(3), (Datediff(minute, StartDateTime, EndDateTime))) / 60 AS 'Hrs Worked' From Table1
这次确实得到了'1.250000'的时长结果,但我无法去掉末尾的零。如果我将decimal(3)替换为decimal(2),会得到如下报错:
Arithmetic overflow error converting int to data type numeric
请问有什么可行的解决方案?
解决方案
原因分析
- 整数除法截断小数:
DATEDIFF函数返回值为int类型,两个整数相除时SQL Server默认执行整数除法,会直接舍弃小数部分,因此75分钟/60得到1而非1.25。 - decimal参数错误导致溢出:
decimal(p,s)的参数中,p为总位数(整数位+小数位之和),s为小数位位数,仅写decimal(2)时默认是decimal(2,0),最多只能存储0~99的整数,若两个时间差超过99分钟,转换时就会触发溢出错误。同时你先转换分钟数再做除法的顺序,会导致最终返回的decimal精度过高,出现多余尾零。
实现方法
方法1:最简写法(自动保留小数)
将除数从60改为60.0,触发浮点除法,无需手动转换类型即可得到带小数的结果:
SELECT startdatetime, enddatetime, DATEDIFF(MINUTE, startdatetime, enddatetime) / 60.0 AS [Hrs worked] FROM table1
方法2:指定精度去除多余尾零
如果需要固定保留2位小数,直接对除法结果做精度转换即可:
SELECT StartDateTime, EndDateTime, CONVERT(DECIMAL(18,2), DATEDIFF(MINUTE, StartDateTime, EndDateTime) / 60.0) AS [Hrs Worked] FROM Table1
这里DECIMAL(18,2)表示总位数18位,小数位保留2位,完全覆盖正常业务的时间差范围,不会出现溢出问题,结果直接为1.25不会有多余尾零。
方法3:自动去除尾零(适配展示需求)
如果需要整小时展示为整数、非整小时保留对应小数(如2小时展示为2,1小时15分展示为1.25),可以使用FORMAT函数(SQL Server 2012及以上版本支持):
SELECT startdatetime, enddatetime, FORMAT(DATEDIFF(MINUTE, startdatetime, enddatetime) / 60.0, '0.##') AS [Hrs worked] FROM table1
内容的提问来源于stack exchange,提问作者R. Pen
相关产品推荐
相关产品推荐

