版本:SQL Server Management Studio v18.9.2
一、函数cast()
1.解决问题
(1)求日期差:起因是由于项目要求,需要计算日期一到日期二之间的差值时,日期类型无法进行减法计算时,需要将日期转化为int类型做减法。
(2)数据类型转变:项目中在做除法时遇到除法时使用count()函数作为分母计数时由于count()函数生成的值数据类型为int,从而导致计算合格率等需要作除的时候结果变成0,需要将count()后的值做数据类型转化,先前查询出count()结果列后对该列单独使用:
alter table + 表名 + alter column + 列名 + float
来更改表结构,从而实现不影响后续做除法生成结果;但后续发现这种情况经常会用到,从而寻找便捷方法。
(3)将数值变为百分比形式
2.测试数据展示
由于项目数据保密,在此模拟一张表来演示使用方法,创一张学生成绩表:
create table 成绩表(
班级 varchar(50),
姓名 varchar(50),
语文成绩 int,
数学成绩 int,
英语成绩 int,
考试日期 datetime,
出成绩日期 datetime
)
表数据展示:
3.cast函数基本使用方法
语法:cast(常量值/列名 as 数据类型)
(1)cast函数作用在常量值上,单独使用一个cast函数
用于数据类型转化:对一个值或一列值进行数据类型转化。
使用cast函数将float数据类型转为int数据类型时,小数部分无论为多少都会舍去,即向下取整。
select cast(5.21 as int) as 小数转整数1
--将float数据类型---->int数据类型,舍去小数点
select cast(8.88 as int) as 小数转整数2
--将float数据类型---->int数据类型,舍去小数点
select cast(5.21 as varchar) as 小数转字符串
--将float数据类型--->字符串类型
(2) cast函数作用在常量值上,嵌套两个或多个cast函数
回到项目需求上,单独使用一个cast函数将日期常量变为int数据类型时会报错,如下图:
解决办法:报错是由于'2025-05-21 08:55:55.000'表现为varchar数据类型,我解决这一问题的方法是使用两个cast函数,先把该varchar数据类型变为datetime数据类型,然后在对其进行int数据类型转化,若对表中的列进行转化则不需要再套一个cast函数。
在转为int类型之前,先看一下各个时间类型的区别,使用的常量’ 2025-05-21 08:55:55.000’为datetime类型。
select cast('2025-05-21 08:55:55.000' as smalldatetime) as 数据类型smalldatetime
,cast('2025-05-21 08:55:55.000' as datetime) as 数据类型datetime
,cast('2025-05-21 08:55:55.000' as date) as 数据类型date
,cast('2025-05-21 08:55:55.000' as time) as 数据类型time
可以看到smalldatetime、datetime、date、time四个时间类型的精度不同,具体区别后续可能会扩展研究和描述,在此不过多赘述。
回到问题本身,对日期常量进行int转化方法如下:嵌套两个cast函数
--按照时间顺序,从5.20下午---->5.22上午
select cast(cast('2025-05-20 13:55:55.000' as datetime) as int) as 五月二十号下午
,cast(cast('2025-05-21 08:55:55.000' as datetime) as int) as 五月二十一号早上
,cast(cast('2025-05-21 11:59:59.000' as datetime) as int) as 五月二十一号上午
,cast(cast('2025-05-21 12:00:00.000' as datetime) as int) as 五月二十一号正午十二点
,cast(cast('2025-05-21 13:55:55.000' as datetime) as int) as 五月二十一号下午
,cast(cast('2025-05-22 08:55:55.000' as datetime) as int) as 五月二十二号早上
根据结果看到的是,虽然将datetime时间数据类型转变为了int数据类型,但是数值是以当天正午十二点为分界点,前一天正午十二点~当天正午十二点之前为一个值,当天正午十二点~次日正午十二点为另一个值。
进一步分析,项目中需要的天数的分界点不是当天正午十二点,而是以当天凌晨零点开始为节点,既然datetime数据类型的时间过于精确,可以选择使用date数据类型,以规避当天的int值不同的问题.。
但是当尝试将date类型转化为int类型时出现了报错信息。
若使用cast函数来确保当天的int值为一个值,就是稍微有点繁琐,但是可以解决。解决方法就是只好再套一个cast转化,顺序为字符串varchar类型—>时间date类型--->时间datetime类型--->int类型
select cast(cast(cast('2025-05-20 13:55:55.000' as date) as datetime) as int) as 五月二十号下午
,cast(cast(cast('2025-05-21 08:55:55.000' as date) as datetime) as int) as 五月二十一号早上
,cast(cast(cast('2025-05-21 11:59:59.000' as date) as datetime) as int) as 五月二十一号上午
,cast(cast(cast('2025-05-21 12:00:00.000' as date) as datetime) as int) as 五月二十一号正午十二点
,cast(cast(cast('2025-05-21 13:55:55.000' as date) as datetime) as int) as 五月二十一号下午
,cast(cast(cast('2025-05-22 08:55:55.000' as date) as datetime) as int) as 五月二十二号早上
(3)cast函数作用在列名上
上面步骤2中创的表中的列 考试日期 和 出成绩日期 数据类型为datetime
首先看一下原始数据:
select 考试日期,出成绩日期 from 成绩表
按照处理常量的同样办法来使得当天的int值为同一个值,确保两天的数值差即为天数差。
select cast(考试日期 as date) as 考试日期
,cast(出成绩日期 as date) as 出成绩日期 from 成绩表
select cast(cast(考试日期 as date) as datetime) as 考试日期
,cast(cast(出成绩日期 as date) as datetime) as 出成绩日期 from 成绩表
select *,cast(cast(cast(考试日期 as date) as datetime) as int) as 考试日期
,cast(cast(cast(出成绩日期 as date) as datetime) as int) as 出成绩日期
,cast(cast(cast(出成绩日期 as date) as datetime) as int)-cast(cast(cast(考试日期 as date) as datetime) as int) as 出成绩所需天数
from 成绩表
如此,问题就解决了。
(4)cast函数与其他聚合函数的结合使用
cast函数与count函数结合使用:假设求成绩的合格率,合格率需要做除法,而count做计数后数据类型为int,需要使用cast函数将count后列名数据类型强转为float,从而做除法。
select 班级,cast(count(姓名) as float) as 班级总人数 from 成绩表
group by 班级
order by 班级 DESC
cast函数与sum函数结合使用:这里还增加了case分支语句,从而筛选语文成绩>=60的数据,当语文成绩>=60时返回1,将返回的结果求和,即是语文成绩>=60的人数。在此case分支语句的详细用法可能会扩展研究和描述,在此先不过多赘述。
select 班级,cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float) as 语文成绩合格人数 from 成绩表
group by 班级
order by 班级 DESC
为了防止做除时分母为0出现除0错误的情况,在此可以再增加一个case分支语句,限定当分母“班级总人数”不为0时,然后做除法求合格率,反之合格率直接返回0。
select 班级,cast(count(姓名) as float) as 班级总人数
,cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float) as 语文成绩合格人数
,case when count(姓名) !=0
then cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float)/cast(count(姓名) as float)
else 0 end as 语文成绩合格率 from 成绩表
group by 班级
order by 班级 DESC
最后进一步更改格式:将合格率的小数变为百分比形式,目前的语文成绩合格率数据类型为float,思路是使用cast函数将语文成绩合格率数据类型改为varchar类型。
具体步骤为:
值(float数据类型)---->值*100(float数据类型)----->值*100(varchar(50))+ ‘%‘
方便看整体格式,选中的标蓝部分为要更改格式的“值”。
select 班级,cast(count(姓名) as float) as 班级总人数
,cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float) as 语文成绩合格人数
,case when count(姓名) !=0
then cast(cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float)/cast(count(姓名) as float)*100 as varchar(50))+'%'
else '0%' end as 语文成绩合格率 from 成绩表
group by 班级
order by 班级 DESC
若需要最后结果保留小数点后几位小数,则可以再套一个round函数,由于是对数字的操作,则需要在变为varchar数据类型之前套round函数。
round函数使用语法为:round(值/列名,要保留几位小数)
select 班级,cast(count(姓名) as float) as 班级总人数
,cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float) as 语文成绩合格人数
,case when count(姓名) !=0
then cast(round(cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float)/cast(count(姓名) as float)*100,2) as varchar(50))+'%'
else '0%' end as 语文成绩合格率 from 成绩表
group by 班级
order by 班级 DESC
4.解决问题
思考到此之后,步骤1所面临的两个问题就可以解决了。整合如下:
select 班级
,case when count(姓名) !=0
then cast(round(cast(sum(case when 语文成绩>=60 then 1 else 0 end) as float)/cast(count(姓名) as float)*100,2) as varchar(50))+'%'
else '0%' end as 语文成绩合格率
,case when count(姓名) !=0
then cast(round(cast(sum(case when 数学成绩>=60 then 1 else 0 end) as float)/cast(count(姓名) as float)*100,2) as varchar(50))+'%'
else '0%' end as 数学成绩合格率
,case when count(姓名) !=0
then cast(round(cast(sum(case when 英语成绩>=60 then 1 else 0 end) as float)/cast(count(姓名) as float)*100,2) as varchar(50))+'%'
else '0%' end as 英语成绩合格率
,cast(cast(cast(出成绩日期 as date) as datetime) as int)-cast(cast(cast(考试日期 as date) as datetime) as int) as 出成绩所需天数
from 成绩表
group by 班级,出成绩日期,考试日期
order by 班级 DESC
二、cast函数使用方法总结
1.使用单独一个cast函数作用于常量值/列名上,更改常量值/列中值的数据类型。
2.两个及以上个cast函数,如求取日期差时多次更改数据类型;做除时,更改分母分子的数据类型。
3.与其他函数搭配使用,如求除时分子分母由count函数、sum函数求得,更改数据格式时与round函数搭配使用保留小数、变百分比形式。
4.延申:case分支语句,防止分母为0。
三、相关链接和资源
1.round函数处理小数位:
SQLSERVER 小数位以及末位处理_sqlserver两个数字相乘保留小数位数-优快云博客
2.百分比处理:
SQLServer_除法_百分比_小数计算_convert(decimal(18,3)-优快云博客
3.case分支语句:
SQL SERVER 多分支的条件语句(case表达式)使用方法_sql分支-优快云博客
4.cast函数用法: