一看到有关日期的简单题目,但要精确计算还是需要一些并不常用的函数。
今天做到一个简单的题目:
要求:1、查询各学生的年龄
2、字段要求及顺序:学号(s_id)、姓名(s_name)、出生日期s_birth。
其中s_birth是char(255)格式,直接用year()函数计算显然会造成不显著偏误。
1.方法1:条件函数
两种实现需求的mysql查询语句如下:
select
s_id
,s_name
,if(month(curdate())-month(s_birth)>0,year(curdate())-year(s_birth),year(curdate())-year(s_birth)-1) as age
from student;
当然if函数也可以用case when语法代替
select s_id
,s_name
,(case when month(s_birth) >= month(curdate()) then year(curdate())-year(s_birth)
else year(curdate())-year(s_birth)-1 end) as age
from student;
思路比较简单:
判断如果当前日期的月份大于出生日期的月份,则直接用年份相减。如果当前日期的月份小于出生日期的月份,则用年份想减得到的差还要减1才能得到年龄。
2.方法2:向下取整
select
s_id
,s_name
,floor( (datediff( curdate(),date(s_birth) ) / 365) ) as age
from student;
3.方法3(最好,推荐,也最准确):时间处理函数
select s_id
,s_name
,timestampdiff(year,str_to_date(s_birth,'%Y-%m-%d'),curdate()) as as age_by_diff
from student;
#str_to_date()函数中的时间序列格式无所谓,timestampdiff()函数都可以识别并计算
此处发现一个问题,下一段代码与上一段代码的区别是使用了date_format函数而不是str_to_date函数,居然得到了一样的结果。这两个函数的数据变化方向实际是完全相反的。涉及到mysql中隐式转换的过程,这里只要知道显式转换优于隐式转换就好,原理个人研究后认为并不能从底层理解,无法推广,只能遇到了特例查询判断就好。这里仅是巧合。
select s_id
,s_name
,timestampdiff(year,date_format(s_birth,'%Y-%m-%d'),curdate()) as as age_by_diff
from student;
总而言之,最优的方法是str_to_date()和timestampdiff()联用解决此问题,思路直接,语法也相对简单,精确度高。
涉及到的函数:
1.if()
IF(expr, if_true_expr, if_false_expr)
expr:要评估的条件表达式(返回 TRUE、FALSE 或 NULL)
if_true_expr:当 expr 为 TRUE(非零且非 NULL)时返回的值
if_false_expr:当 expr 为 FALSE 或 NULL 时返回的值
2.floor(x)
向下取整。(和ceiling()的功能恰好相反)
例如:
x=3.7,会输出3.
x=3.2,依旧会输出3
3.STR_TO_DATE() 和DATE_FORMAT()函数
STR_TO_DATE() 是 MySQL 中用于将字符串转换为日期时间值的函数,特别适用于将非标准格式的日期字符串转换为 MySQL 可识别的日期时间格式。
相反的,DATE_FORMAT()函数是将日期时间值格式化为字符串的函数。
实际应用场景
DATE_FORMAT() 典型用途:
在报表中显示格式化的日期
将日期转换为特定格式用于导出
在应用程序界面中显示用户友好的日期格式
STR_TO_DATE() 典型用途:
导入非标准格式的日期数据
处理用户输入的日期字符串
将文本文件中的日期转换为数据库可识别的格式
语法
STR_TO_DATE(str, format)
str:要转换的日期时间字符串
format:指定输入字符串的格式
DATE_FORMAT(date, format)
date:DATE、DATETIME或TIMESTAMP类型的值
format:指定输出格式的格式字符串
这里想要看一下两种函数输出的数据类型,可以用以下方法。创建一个临时表后用
create temporary table temp_table as
(select date_format('20050312',"%Y%m%d")) limit 0;
describe temp_table;
drop temporary table temp_table;
#limit 0 表示只引入表结构而不包含数据
看到type类型显示的是varchar(8)。
create temporary table temp_table as
(select timestamp(date_format('20050312',"%Y%m%d"))) limit 0;
describe temp_table;
drop temporary table temp_table;
看到type类型显示的是datetime。
create temporary table temp_table as
(select str_to_date('20050312',"%Y%m%d")) limit 0;
describe temp_table;
drop temporary table temp_table;
看到type类型显示的是date。