最近在Phpfreaks.com论坛上提出了一个问题,即有人使用MySQL数据库存储用户出生日期的最佳方式。一个人建议使用varchar,因为他们最熟悉字符串函数。我的回答是使用MySQL日期类型。

我提供了一个快速的“使用日期的优点”比较列表:
存储为日期
•MySQL日期需要3个字节的存储空间
•您可以在mysql内部执行日期算术(搜索范围内的日期)并使用mysql函数直接计算值查询
•它本质上只存储有效日期
•您可以通过多种方式对其进行格式化

存储为Varchar
•字符串最少需要8个字节,或者10个字符串需要分隔符
•不能执行任何形式的高效本机范围查询
•无法在SQL中轻松地重新格式化
•将允许完全无效的日期

我认为这是一个很好的证明方法是表明你可以让MySQL使用他们的生日计算查询中人的当前年龄。当然使用字符串,例如使用PHP,您通常会查询数据库以提取字符串,并为每一行,将其转换为PHP日期并在代码中进行一些计算,然后您到达同一个地方,但是我想展示SQL的能力 - 在这种情况下,MySQL可以特别是当你使用本机数据类型和一些功能时。

在MySQL查询中计算一个人的年龄

我之前写过关于CURDATE()的文章,它可以让你访问“当前服务器日期”作为比较计算的基础。

要计算一个人当前的年龄,简单的食谱是“今年”减去“出生年份”。

使用MySQL Date类型存储用户生日的优点是,您可以使用YEAR()这样的简单函数来为您提供所需日期的任何部分。

mysql 选择 YEAR  CURDATE  ; 
+ ----------------- + 
 CURDATE  
+ ----------------- + 
           2011 
+ ----------------- + 
1行 集合 0.00秒

为了测试这个概念,我们将创建一个简单的用户表,其中包含密钥,名称和生日。

CREATE TABLE用户( id int AUTO_INCREMENT PRIMARY KEY , name varchar (20 ), birthdate date ) ;

mysql > describe user; 
+ ----------- ------------- + + ------ + ------ + --------- + ---------------- + 
领域     输入         钥匙默认额外的           
+ ----------- ------------- + + ------ + ------ + --------- + ---------------- + 
id        int 11      没有   PRI NULL     auto_increment 
名字       varchar 20  |是的       NULL                    
生日日期        是的       NULL                    
+ ----------- ------------- + + ------ + ------ + --------- + ---------------- + 
3行 集合 0.27秒

现在我们将添加一些用户行:

INSERT INTO用户(姓名,生日) VALUES ('Fran' , '1967-10-31' ) ; 
INSERT INTO用户(姓名,生日) VALUES ('Bill' , '1964-05-07' ) ; 
INSERT INTO用户(姓名,生日) VALUES ('Jimmy' , '1965-04-27' ) ; 
INSERT INTO用户(名称,生日) VALUES ('Stacy' , '2002-11-30' ) ; 
INSERT INTO用户(姓名,生日) VALUES ('George' , '2007-10-25' ) ;

mysql select * from user; 
+ ---- + -------- + ------------ + 
id 名字   生日   
+ ---- + -------- + ------------ + 
 1 弗兰   1967 - 10 - 31 
 2 比尔   1964年 - 05 - 07年
 3 吉米   1965 -04- 27 
 4 Stacy   2002 - 11 -30 
 5 乔治2007 - 10 - 25 
+ ---- + -------- + ------------ + 
5行 集合 0.00秒

我们关于年龄计算的第一个传递将涉及实施当前年份 - 出生年份:

随着本教程的老化,请注意这些查询的结果可能会根据当前日期而有所不同,如果您选择自己运行它们(我强烈推荐) )。这些结果与:

mysql select CURDATE  ; 
+ ------------ + 
CURDATE   
+ ------------ + 
2011 -08- 11 
+ ------------ + 
1行 集合 0.00秒

SELECT *, YEAR ( CURDATE ()) - YEAR ( birthdate ) AS age FROM user;

mysql > SELECT *,YEAR  CURDATE  - YEAR  birthdate  AS age FROM user;              
+ ---- + -------- + ------------ + ------ + 
id 名字   生日   年龄   
+ ---- + -------- + ------------ + ------ + 
 1 弗兰   1967 - 10 - 31   44 
 2 比尔   1964年 - 05 - 07年|   47 
 3 吉米   1965 -04- 27   46 
 4 Stacy   2002 - 11 - 30    9 
 5 乔治2007 - 10 - 25    4 
+ ---- + -------- + ------------ + ------ + 
5行 集合 0.00秒

调整即将到来的生日的人的年龄

现在,如果你看一下这些结果,你可能已经注意到了一个问题。例如,2007年10月25日出生的“乔治”还不到4岁,因为它只是8月11日,而他的生日还没有发生。
因此,乔治仍然是3岁。因此,在此计算中确定“今天”是否小于您的生日纪念日是很重要的。正如我之前演示的那样,mysql提供了一个有用的三元函数IF(),可以让你解决这些“if then else”场景。但首先我们需要确定用户的出生日期是否已经过去了?

我们能做的是让MySQL根据您的出生日(月和日)和当前年份制作日期,并将其与curdate()进行比较。如果curdate()是>我们制造的“
从年龄减去一年,以反映他们的生日在当年没有发生。

逐个组装查询

我们将使用STR_TO_DATE(在MySQL 4.1.1版中引入)来创建mysql计算的“生日”日期。STR_TO_DATE采用您选择的格式的字符串,并将其转换为mysql日期。如'%Y-%c-%e'参数所示,我们将使用带有前导零的'YEAR-MO-DA'作为月份和日期。破折号不是必需的,但我使用它们可以很容易地将我们制造的日期字符串与生日专栏进行比较。内部mysql正在使用数字,最终输出的格式是您可以使用像DATE_FORMAT这样的函数在查询中控制的。

SELECT *, STR_TO_DATE ( CONCAT ( YEAR ( CURDATE ()), ' - ' ,月(生日), ' - ' , DAY (出生日期)) ,'%Y-%C-%E' ) AS生日FROM用户;

mysql > SELECT *,STR_TO_DATE  CONCAT  YEAR  CURDATE ,' - ',MONTH 生日,' - ',DAY 生日,'%Y-%c-%e'  作为来自用户的生日; 
+ ---- + -------- + ------------ + ------------ + 
id 名字   生日   生日   
+ ---- + -------- + ------------ + ------------ + 
 1 |弗兰   1967 - 10 - 31 2011 - 10 - 31 
 2 比尔   1964年 - 05 - 07年2011年 -05-07 
 3 吉米   1965 -04- 27 2011 -04- 27 
 4 Stacy   2002 - 11 - 30 2011 - 11 - 30 | 
 5 乔治2007 - 10 - 25 2011 - 10 - 25 
+ ---- + -------- + ------------ + ------------ + 
5行 集合 0.00秒

现在我们将利用IF()来进行比较,并在必要时减去一年。IF()需要3个参数:

•要检查的条件
•条件为真时
返回的值•条件为假时返回的值

只是对于可视化验证,让我们首先将三元函数添加到先前查询的末尾。一个将指示用户的生日没有发生,零将指示它已经发生。当然,这些也是
我们将减去年龄计算结果来修复它的值!

SELECT *, STR_TO_DATE ( CONCAT ( YEAR ( CURDATE ()), ' - ' , MONTH (出生日期), ' - ' , DAY (出生日期)) ,'%Y-%C-%E' ) AS生日,
IF ( STR_TO_DATE ( CONCAT ( YEAR ( CURDATE ()), ' - ' ,月(生日), ' - ' ,DAY (出生日期)) ,'%Y-%C-%E' ) > CURDATE (), 1 , 0 ) AS调整
FROM用户;

+ ---- + -------- + ------------ + ------------ + --------- --- + 
id 名字   生日   生日   调整
+ ---- + -------- + ------------ + ------------ + --------- --- + 
 1 弗兰   1967 - 10 - 31 2011 - 10 - 31          1 
 2 比尔   1964年 - 05 - 07年2011年 -05-07          0 
 3 吉米   1965 -04- 27 2011 -04- 27          0 
 4 Stacy   2002 - 11 - 30 2011 - 11 - 30          1 
 5 乔治2007 - 10 - 25 2011 - 10 - 25          1 
+ ---- + -------- + ------------ + ------------ + --------- --- + 
5行  0.00秒

10月和11月生日的3个人应该正确调整年龄。我们将其添加到原始年龄计算中,现在我们的年龄是准确的:

SELECT *, YEAR ( CURDATE ()) - 
YEAR (出生日期) - 
IF ( STR_TO_DATE ( CONCAT ( YEAR ( CURDATE ()), ' - ' , MONTH (出生日期),' - ' , DAY (出生日期)) ,“%Y - %C-%E” ) > CURDATE (), 1 , 0 ) 
AS年龄来自用户;

+ ---- + -------- + ------------ + ------ + 
id 名字   生日   年龄   
+ ---- + -------- + ------------ + ------ + 
 1 弗兰   1967 - 10 - 31   43 
 2 比尔   1964年 - 05 - 07年  47 
 3 吉米   1965 -04- 27   46 
 4 Stacy   | 2002 - 11 - 30    8 
 5 乔治2007 - 10 - 25    3 
+ ---- + -------- + ------------ + ------ + 
5行 集合 0.00秒

我们根据mysql birthdate date列计算Age!

闰年

格里高利日历中的闰年是将我们的365天日历与现实同步的调整,因为实际上需要花费365天以上的时间让地球绕太阳旋转一次。数学计算出来,你
只需要每4年增加一天,那一天是2月29日。2012年是闰年,因为它可以被4整除。闰年规则并不是那么简单:

•如果年份是百年,则不是闰年
•除非那一年可以被400整除| 
否则,如果可以被4整除,那就是闰年

有一个边缘情况使这项任务复杂化。在闰年2月29日出生的人,每4年只在他们的实际“出生日”生日。通常,闰年出生的人的解决方案
是在二月的最后一天庆祝他们的生日,即28日或29日。对于我们的年龄计算,这实际上只是每年一天的问题。例如,我们可以假设
如果您是闰年宝宝,我们只会将您的出生日期视为第28天,并且您的年龄计算仅为每4年一天不正确。这是一个很容易证明合理的权衡。如图所示
令人惊讶的是,即使我们使用无效日期来将它们与curdate()进行比较,查询上方甚至会对2月29日的婴儿起作用。但是,MySQL可以做得更好。

添加计算以处理闰年婴儿

让我们在数据库中添加一个闰年宝贝,这样我们就可以测试出来:

INSERT INTO用户(姓名,生日) VALUES ('Leapie' , '2008-02-29' ) ;

mysql > insert into user  name,birthdate  values 'Leapie','2008-02-29'  ; 
查询OK,1行受影响0.00秒

mysql select * from user;                                                                                          
+ ---- + -------- + ------------ + 
id 名字   生日   
+ ---- + -------- + ------------ + 
 1 弗兰   1967年 -10 - 31 
 2 比尔   1964年 - 05 - 07年
 3 吉米   1965 -04- 27 
 4 Stacy   2002 - 11 - 30 
 5 乔治2007 - 10 - 25 
 6 Leapie 2008 -02- 29 
+ ---- + -------- + ------------ + 
6行  0.00秒

如果您尝试插入无效日期会怎样?MySQL将生成警告,并创建一个充满零的日期。除非您将其配置为允许无效日期,否则它不会存储无效日期。因此,如果你尝试插入2011年2月29日的生日,mysql将不会让你。

mysql > insert into user  name,birthdate  values 'BadLeap','2011-02-29'  ; 
查询OK,1行受影响,1警告0.00秒

mysql > SHOW WARNINGS; 
+ --------- + ------ + -------------------------------- ---------------- + 
等级   代码消息                                         
+ --------- + ------ + -------------------------------- ---------------- + 
警告1265 数据截断列“生日”在行1 
+ --------- + ------ + -------------------------------- ---------------- + 
1行 集合 0.00秒

的MySQL 选择 *从用户; 
+ ---- + --------- + ------------ + 
id 名字     生日   
+ ---- + --------- + ------------ + 
 1 弗兰     1967 - 10 - 31 
 2 |比尔     1964年 - 05 - 07年
 3 吉米   1965 -04- 27 
 4 Stacy   2002 - 11 - 30 
 5 乔治   2007 - 10 - 25 
 6 Leapie   2008 -02- 29 
 7 BadLeap 0000-00-00 | 
+ ---- + --------- + ------------ + 
7行 集合 0.00秒

令人惊讶的是,MySQL将允许您构建无效日期,甚至将它们与STR_TO_DATE一起使用,即使它不允许存储无效日期:

mysql > SELECT STR_TO_DATE '2011-02-29','%Y-%c-%e'  作为生日; 
+ ------------ + 
生日   
+ ------------ + 
2011 -02- 29 
+ ------------ + 
1行 集合 0.00秒

的MySQL > SELECT STR_TO_DATE '2011年2月31日','%Y-%C-%E'  生日; 
+ ------------ + 
生日   
+ ------------ + 
2011-02- 31 
+ ------------ + 
1行 集合 0.00秒

的MySQL > SELECT STR_TO_DATE '2011-09-30' ,'%Y-%C-%E'  生日; 
+ ------------ + 
生日   
+ ------------ + 
2011 -09- 30 
+ ------------ + 
1行 集合 0.00秒

的MySQL > SELECT STR_TO_DATE '2011年9月31日','%Y-%c-%e'  作为生日; 
+ ------------ + 
生日   
+ ------------ + 
2011 -09- 31 
+ ------------ + 
1行 集合 0.00秒

的MySQL > SELECT STR_TO_DATE '2011-09-32' ,'%Y-%C-%E'  生日; 
+ ---------- + 
生日
+ ---------- + 
NULL     
+ ---------- + 
1行 集合,1警告0.00秒

mysql > SELECT STR_TO_DATE '2011-13-32','%Y-%c-%e'  作为生日; 
+ ---------- + 
生日
+ ---------- + 
NULL     
+ ---------- + 
1行 集合,1个警告0.00秒

的MySQL > SELECT STR_TO_DATE '2011-13-11' ,'%Y-%C-%E'  生日;
+ ---------- + 
生日
+ ---------- + 
NULL     
+ ---------- + 
1行 集合,1个警告0.00秒

的MySQL > SELECT STR_TO_DATE '2011-00-11' ,'%Y-%C-%E'  生日;  
+ ------------ + 
生日   
+ ------------ + 
2011 -00- 11 
+ ------------ + 
1行 集合 0.00秒

这部分是设计,部分是配置问题。当前版本的MySQL允许您调整服务器中的设置,以指示它将如何处理无效日期。关于闰年的大部分担忧都是学术上的。 
我们并不需要担心闰年规则,除非年份可以被4整除,即便如此,由于我们可以安全地构建无效日期以进行比较,即使没有
闰年调整,闰年生日的年龄计算只会在一年中一天不正确,即使我们只使用上面提供的忽略2月29日问题的查询。

至少有几种不同的方法可以解决这个问题:

•确定当前年份是否为非闰年并使用第28年
•让mysql弄清楚2月的最后一天是什么,并将其作为当天使用。

在任何一种情况下,我们都需要使用三元IF()添加到现有查询中。

在MySQL查询中计算一个人的年龄相关推荐

  1. mysql查询到最新记录就停止_使用Limit参数优化MySQL查询 在找到一个记录后将停止查询...

    优化 MySQL 查询的 Limit 参数 我们在做一些查询的时候总希望能避免数据库引擎做全表扫描,因为全表扫描时间长,而且其中大部分扫描对客户端而言是没有意义的.那么在 MySQL 中有那些方式是可 ...

  2. java精准查询mysql时间_在mysql查询中查找与指定日期时间最接近的日期时间

    我试图在mysql数据库中找到一个datetime值,它与我指定的日期时间最接近,我遇到了一些麻烦 . 以下伪代码是我想要实现的: SELECT one FROM table WHERE dateti ...

  3. python统计列表中元素个数_python中计算一个列表中连续相同的元素个数方法

    python中计算一个列表中连续相同的元素个数方法 最简单的例子: a = [1,1,1,1,2,2,2,3,3,1,1,1,3] # 问:计算a中最多有几个连续的1 很明显,答案是4 如果用代码实现 ...

  4. mysql 空集 赋值_如何在MySQL查询中替换“空集”?

    要替换不存在的记录,请在MySQL中使用COALESCE.COALESCE将有助于替换NULL值.让我们首先创建一个表-create table DemoTable -> ( -> Cod ...

  5. mysql数据中计算时间差函数

    mysql数据中计算时间差函数 MySql计算两个日期的时间差函数TIMESTAMPDIFF用法: 语法: TIMESTAMPDIFF(interval,datetime_expr1,datetime ...

  6. MySQL查询中LIMIT的大offset导致性能低下浅析

    这篇文章主要给大家介绍了关于MySQL查询中LIMIT的大offset导致性能低下的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起 ...

  7. EF Core For MySql查询中使用DateTime.Now作为查询条件的一个小问题

    背景 最近一直忙于手上澳洲线上项目的整体迁移和升级的准备工作,导致博客和公众号停更.本周终于艰难的完成了任务,借此机会,总结一下项目中遇到的一些问题. EF Core 一直是我们团队中中小型项目常用的 ...

  8. mysql查询并计算单价_Mysql--查询的成本如何计算

    查询成本组成有哪些. 1.I/O成本 2.CPU成本 3.Mysql规定读取一个页面花费的成本默认是1.0,读取以及检测一条记录是否符合搜索条件的成本默认是0.2.1.0.0.2这些数字称之为成本常数 ...

  9. mysql更新id最大_我们可以在单个MySQL查询中更新具有最高ID的行吗?

    是的,我们可以做到.让我们首先创建一个表-mysql> create table DemoTable ( ID int, GameScore int ); 使用插入命令在表中插入一些记录-mys ...

最新文章

  1. 公钥与私钥,HTTPS详解
  2. 2021年下信息系统项目管理师真题各章节占分比
  3. Docker swarm - 使用体验 1+2
  4. boost::locale::to_upper用法的测试程序
  5. vision画流程图的软件_产品流程图的定义,作用和画法
  6. HTML5火焰文字特效DEMO演示---转载
  7. 扬尼斯定律:程序员的开发效率每6年提高一倍
  8. 进程的控制——获取系统进程信息
  9. 关于计算机人工智能的知识,《计算机科学导论》人工智能基础知识
  10. php 请求header,PHP的curl查看header信息的功能(包括查看返回header和请求header)
  11. 在吗?我要讲件大事了,你绝对不知道CSDN公众号还有这个功能!错过后悔!
  12. 工具的使用 —— windows 实用工具
  13. 如何运行网上下载的matlab代码?怎样找到matlab主程序?
  14. ACEL计算机证书,FSHW:酪蛋白水解物衍生的双功能肽的体外和计算机分析
  15. Hdu 5064 Find Sequence 解题报告
  16. Tumblr面试流程
  17. 19款最好用的免费数据挖掘工具大汇总
  18. 二年级课程表(4月18日-4月22日)
  19. 一文详解!你真的了解商业智能BI吗?
  20. 科学划定“三区三线” 严格保护与合理利用自然资源

热门文章

  1. 培训教育系统阶段性效果展示
  2. 谈谈自己对机器学习如何学习以及未来职业方向的理解(不断更新中)
  3. StarUML安装破解及使用简明教程
  4. 10-1.WPF模板
  5. 变频器零速满转矩的理解
  6. 4核处理器_主流网游配置:4核处理器+RX580显卡,两千五就吃鸡还要啥自行车
  7. 微服务架构-测试理解
  8. draft-ietf-quic-load-balancers-14
  9. scratch3.0无法连接wedo2.0
  10. 模块化设计方案-20221114