基于【MySQL】的【SQL核心语法】实战演练(二)

说明

本文基于【MySQL】,使用命令行,继续实战讲解【SQL】的基本语法。
上一篇文章在MySQL系统命令、数据库建库建表删库删表、增删改查基本操作的基础上,主要讲了LIMIT、LIKE、IN、BETWEEN、AS、INSERT INTO SELECT、JOIN、UNION、CONTRAINT、INDEX等内容。
而本文会主要围绕MySQL,继续讲解很多重要的SQL语法,这些不算很难的知识,但也比最基本的insert、delete、update、select要高级很多了。阅读之前,请务必学会基本的增删改查(可以阅读下面的“必知必会”文章)。

必知必会

《MySQL系统命令+基础查询总结》
《MySQL命令行测试基础SQL》
《基于MySQL的SQL核心语法实战演练(一)》

全表查询

先查查stu_grade这个表有什么原始数据:

mysql> select * from stu_grade;
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  1 | Sam    |     120 |  145 |     145 |   410 |
|  2 | Bob    |      88 |   98 |      95 |   278 |
|  3 | Steven |     130 |  108 |     135 |   373 |
|  4 | Amy    |     120 |  120 |     120 |   360 |
|  5 | Eleven |     130 |  130 |     140 |   400 |
|  6 | Miffy  |     125 |  145 |     135 |   405 |
+----+--------+---------+------+---------+-------+
6 rows in set (0.00 sec)

全表结构查询

然后还需要查查表的结构,知道有哪些约束、属性、类型等等:

mysql> show create table stu_grade;
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                 |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu_grade | CREATE TABLE `stu_grade` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `chinese` int(11) DEFAULT '0',
  `math` int(11) DEFAULT '0',
  `english` int(11) DEFAULT '0',
  `grade` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

ALTER TABLE 语句

ALTER TABLE 语句用于在已有的表中添加、删除或修改列。

“增”的标准SQL语法:

ALTER TABLE table_name
ADD column_name datatype

“删”的标准SQL语法:

ALTER TABLE table_name
DROP COLUMN column_name

而我们使用MySQL更改表中列的数据类型,应该这么写(Oracle也是,但SQL Server不同):

ALTER TABLE table_name
MODIFY COLUMN column_name datatype

所以,我们试图把int类型的成绩属性换成varchar(10)类型的:

mysql> alter table stu_grade
    -> modify column grade varchar(10);
Query OK, 6 rows affected (1.76 sec)
Records: 6  Duplicates: 0  Warnings: 0

查看一下表的结构,发现grade属性变成了varchar(10)类型的:

mysql> show create table stu_grade;
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                     |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu_grade | CREATE TABLE `stu_grade` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `chinese` int(11) DEFAULT '0',
  `math` int(11) DEFAULT '0',
  `english` int(11) DEFAULT '0',
  `grade` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

既然改了,那我们总要改回来吧,于是同理可以换回来:

mysql> alter table stu_grade
    -> modify column grade int;
Query OK, 6 rows affected (1.20 sec)
Records: 6  Duplicates: 0  Warnings: 0

查看一下表的结构,发现grade属性恢复了int类型的:

mysql> show create table stu_grade;
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                 |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu_grade | CREATE TABLE `stu_grade` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `chinese` int(11) DEFAULT '0',
  `math` int(11) DEFAULT '0',
  `english` int(11) DEFAULT '0',
  `grade` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

AUTO INCREMENT字段

AUTO_INCREMENT 会在新记录插入表中时生成一个唯一的数字,而不必非要自己指定。

AUTO_INCREMENT 字段在不同数据库中是不同的,我们这里只说MySQL。

在测试这个的时候,由于表结构已经存在,所以没玩明白,犯了不少错误。错误在此不一一列举了,防止误导大家。

我们可以直接使用 ALTER TABLE 重新指定需要改的列的全部约束(除了主键约束,你要是试图再补一下主键约束是会报错的呀)(另强调,默认的情况就是很简单的当前+1):

mysql> alter table stu_grade change id id int not null auto_increment;
Query OK, 6 rows affected (1.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

既然这玩意已经存在了,那我们不如插一条数据试试,只需要不指定id即可,但其他的我也不希望是NULL或者不能为NULL:

mysql> insert into stu_grade (name, chinese, math, english, grade) values
    -> ('Smith', '100', '100', '100', '300');
Query OK, 1 row affected (0.18 sec)

查表看看:

mysql> select * from stu_grade;
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  1 | Sam    |     120 |  145 |     145 |   410 |
|  2 | Bob    |      88 |   98 |      95 |   278 |
|  3 | Steven |     130 |  108 |     135 |   373 |
|  4 | Amy    |     120 |  120 |     120 |   360 |
|  5 | Eleven |     130 |  130 |     140 |   400 |
|  6 | Miffy  |     125 |  145 |     135 |   405 |
|  7 | Smith  |     100 |  100 |     100 |   300 |
+----+--------+---------+------+---------+-------+
7 rows in set (0.00 sec)

成功啦!

视图相关

这里只说一些最基本的视图相关,视图算得上是中级的SQL语法了,后面会再总结的。

创建视图的标准SQL语句:

CREATE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition

更新视图的标准SQL语句:

CREATE OR REPLACE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition

删除视图的标准SQL语句:

DROP VIEW view_name

那我们就自己创建一个视图看看,属性选id、name、grade:

mysql> create view grade_view as
    -> select id, name, grade
    -> from stu_grade;
Query OK, 0 rows affected (0.47 sec)

视图全图查询:

mysql> select * from grade_view;
+----+--------+-------+
| id | name   | grade |
+----+--------+-------+
|  1 | Sam    |   410 |
|  2 | Bob    |   278 |
|  3 | Steven |   373 |
|  4 | Amy    |   360 |
|  5 | Eleven |   400 |
|  6 | Miffy  |   405 |
|  7 | Smith  |   300 |
+----+--------+-------+
7 rows in set (0.01 sec)

删除视图:

mysql> drop view grade_view;
Query OK, 0 rows affected (0.45 sec)

这些操作很low的,以后再说高级的。

NULL相关

NULL 值代表遗漏的未知数据。
说道这个NULL,不知你可想到那位(java.lang.NullPointerException),哈哈哈哈~
如果指定 NOT NULL约束,就不允许该属性出现未知空值;否则默认可以为空且不插入就为NULL。
也就是说,如果表中的某个列是可选且可以为NULL的,那么我们可以在不向该列添加值的情况下插入新记录或更新已有的记录。这意味着该字段将以 NULL 值保存。

关于NULL,要知道几件事:

  • NULL 用作未知的或不适用的值的占位符。
  • NULL 和 0 不等价,无法比较。
  • NULL 值的处理方式与其他值不同。
  • 比较重要且不该为空的数据建议使用NOT NULL约束。
  • 判断NULL不需要引号,也不应该使用等号,而是应该使用 IS NULL or IS NOT NULL。

表的NULL预处理

我们看一下都有什么表:

mysql> show tables;
+-----------------+
| Tables_in_test  |
+-----------------+
| stu_best_friend |
| stu_grade       |
| stu_info        |
+-----------------+
3 rows in set (0.01 sec)

对,看一下stu_best_friend这个表的结构:

mysql> show create table stu_best_friend;
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table           | Create Table                                                                                                                                                                             |
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu_best_friend | CREATE TABLE `stu_best_friend` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `friend_name` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

然后就可以调整允许属性为NULL啦(撤销NOT NULL约束):

mysql> alter table stu_best_friend
    -> modify friend_name varchar(10) null;
Query OK, 0 rows affected (1.32 sec)
Records: 0  Duplicates: 0  Warnings: 0

重新查看表结构,发现修改成功:

mysql> show create table stu_best_friend;
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table           | Create Table                                                                                                                                                                                 |
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu_best_friend | CREATE TABLE `stu_best_friend` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `friend_name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

插入NULL数据

我们先看看表里原来有什么数据:

mysql> select * from stu_best_friend;
+----+-------+-------------+
| id | name  | friend_name |
+----+-------+-------------+
|  1 | Sam   | Tim         |
|  2 | Bob   | Sam         |
|  3 | Haris | Rookie      |
|  7 | Kitty | Miffy       |
+----+-------+-------------+
4 rows in set (0.00 sec)

然后就插入一条记录,friend_name属性不赋值,默认为NULL:

mysql> insert into stu_best_friend (id, name) values
    -> ('8', 'Green');
Query OK, 1 row affected (0.42 sec)

查一下:

mysql> select * from stu_best_friend;
+----+-------+-------------+
| id | name  | friend_name |
+----+-------+-------------+
|  1 | Sam   | Tim         |
|  2 | Bob   | Sam         |
|  3 | Haris | Rookie      |
|  7 | Kitty | Miffy       |
|  8 | Green | NULL        |
+----+-------+-------------+
5 rows in set (0.00 sec)

成功的话,就多插入几条记录吧:

mysql> insert into stu_best_friend (id, name) values
    -> ('9', 'Oriana'),
    -> ('10', 'JiNitaimei');
Query OK, 2 rows affected (0.40 sec)
Records: 2  Duplicates: 0  Warnings: 0

验证一下:

mysql> select * from stu_best_friend;
+----+------------+-------------+
| id | name       | friend_name |
+----+------------+-------------+
|  1 | Sam        | Tim         |
|  2 | Bob        | Sam         |
|  3 | Haris      | Rookie      |
|  7 | Kitty      | Miffy       |
|  8 | Green      | NULL        |
|  9 | Oriana     | NULL        |
| 10 | JiNitaimei | NULL        |
+----+------------+-------------+
7 rows in set (0.00 sec)

使用IS NULL筛选NULL

我们在WHERE子句中使用IS NULL判断friend_name空的人:

mysql> select * from stu_best_friend
    -> where friend_name is null;
+----+------------+-------------+
| id | name       | friend_name |
+----+------------+-------------+
|  8 | Green      | NULL        |
|  9 | Oriana     | NULL        |
| 10 | JiNitaimei | NULL        |
+----+------------+-------------+
3 rows in set (0.00 sec)

反过来,也可以使用IS NOT NULL筛选friend_name非空的人:

mysql> select * from stu_best_friend
    -> where friend_name is not null;
+----+-------+-------------+
| id | name  | friend_name |
+----+-------+-------------+
|  1 | Sam   | Tim         |
|  2 | Bob   | Sam         |
|  3 | Haris | Rookie      |
|  7 | Kitty | Miffy       |
+----+-------+-------------+
4 rows in set (0.00 sec)

MySQL支持的IFNULL()函数

我们在前面也说了,NULL 用作未知的或不适用的值的占位符,也就是说NULL也许不是我们想要的或者需要我们处理一下的。
幸运的是,MySQL支持的IFNULL()函数正好帮助我们去规定如何处理 NULL 值。
比如下面的代码,当friend_name时NULL的时候,查出来的是DK(Don’t Know):

mysql> select id, name, ifnull(friend_name, 'DK')
    -> from stu_best_friend;
+----+------------+---------------------------+
| id | name       | ifnull(friend_name, 'DK') |
+----+------------+---------------------------+
|  1 | Sam        | Tim                       |
|  2 | Bob        | Sam                       |
|  3 | Haris      | Rookie                    |
|  7 | Kitty      | Miffy                     |
|  8 | Green      | DK                        |
|  9 | Oriana     | DK                        |
| 10 | JiNitaimei | DK                        |
+----+------------+---------------------------+
7 rows in set (0.00 sec)

MySQL支持的COALESCE()函数

COALESCE()和IFNULL()感觉一样,这里体验感差不多:

mysql> select id, name, coalesce(friend_name, 'DK')
    -> from stu_best_friend;
+----+------------+-----------------------------+
| id | name       | coalesce(friend_name, 'DK') |
+----+------------+-----------------------------+
|  1 | Sam        | Tim                         |
|  2 | Bob        | Sam                         |
|  3 | Haris      | Rookie                      |
|  7 | Kitty      | Miffy                       |
|  8 | Green      | DK                          |
|  9 | Oriana     | DK                          |
| 10 | JiNitaimei | DK                          |
+----+------------+-----------------------------+
7 rows in set (0.00 sec)

再次改变表结构

改变表结构是为了后面的DATE相关测试。

先查看表的结构:

mysql> show create table stu_info;
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                                                                                                                                    |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu_info | CREATE TABLE `stu_info` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `age` int(11) NOT NULL,
  `email` varchar(20) DEFAULT NULL,
  `country` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

接下来插入新的列,该列名为birthday,类型是date,非空,默认值是’2000-1-1’:

mysql> alter table stu_info
    -> add column birthday date
    -> not null
    -> default '2000-1-1';
Query OK, 0 rows affected (0.59 sec)
Records: 0  Duplicates: 0  Warnings: 0

全表查询,发现插在了最后(但我们想要在age之后):

mysql> select * from stu_info;
+----+--------+-----+---------------------+---------+------------+
| id | name   | age | email               | country | birthday   |
+----+--------+-----+---------------------+---------+------------+
|  1 | Sam    |  19 | 123456789@qq.com    | China   | 2000-01-01 |
|  2 | Bob    |  20 | bobbob@gmail.com    | USA     | 2000-01-01 |
|  3 | Steven |  21 | steven521@gmail.com | UK      | 2000-01-01 |
|  4 | Amy    |  19 | amy20205205@163.com | China   | 2000-01-01 |
|  5 | Eleven |  20 | 11more11@163.com    | China   | 2000-01-01 |
|  6 | Miffy  |  24 | miffy521@126.com    | Japan   | 2000-01-01 |
+----+--------+-----+---------------------+---------+------------+
6 rows in set (0.00 sec)

于是可以删掉该列:

mysql> alter table stu_info
    -> drop column birthday;
Query OK, 0 rows affected (1.10 sec)
Records: 0  Duplicates: 0  Warnings: 0

确认删除:

mysql> select * from stu_info;
+----+--------+-----+---------------------+---------+
| id | name   | age | email               | country |
+----+--------+-----+---------------------+---------+
|  1 | Sam    |  19 | 123456789@qq.com    | China   |
|  2 | Bob    |  20 | bobbob@gmail.com    | USA     |
|  3 | Steven |  21 | steven521@gmail.com | UK      |
|  4 | Amy    |  19 | amy20205205@163.com | China   |
|  5 | Eleven |  20 | 11more11@163.com    | China   |
|  6 | Miffy  |  24 | miffy521@126.com    | Japan   |
+----+--------+-----+---------------------+---------+
6 rows in set (0.00 sec)

重新插入,使用after表明在age属性之后:

mysql> alter table stu_info
    -> add column birthday date
    -> not null
    -> default '2000-1-1'
    -> after age;
Query OK, 0 rows affected (1.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

全表查询,最终得到想要的插入顺序:

mysql> select * from stu_info;
+----+--------+-----+------------+---------------------+---------+
| id | name   | age | birthday   | email               | country |
+----+--------+-----+------------+---------------------+---------+
|  1 | Sam    |  19 | 2000-01-01 | 123456789@qq.com    | China   |
|  2 | Bob    |  20 | 2000-01-01 | bobbob@gmail.com    | USA     |
|  3 | Steven |  21 | 2000-01-01 | steven521@gmail.com | UK      |
|  4 | Amy    |  19 | 2000-01-01 | amy20205205@163.com | China   |
|  5 | Eleven |  20 | 2000-01-01 | 11more11@163.com    | China   |
|  6 | Miffy  |  24 | 2000-01-01 | miffy521@126.com    | Japan   |
+----+--------+-----+------------+---------------------+---------+
6 rows in set (0.00 sec)

但由于我们围绕20岁内置过年龄,这不匹配,所以强行改一下年龄(注意参考VB,<>表示!=,而这里并没有!=这种写法):

mysql> update stu_info
    -> set age=20
    -> where age<>20;
Query OK, 4 rows affected (0.42 sec)
Rows matched: 4  Changed: 4  Warnings: 0

查一下,嘿嘿,全是千禧宝宝啦!

mysql> select * from stu_info;
+----+--------+-----+------------+---------------------+---------+
| id | name   | age | birthday   | email               | country |
+----+--------+-----+------------+---------------------+---------+
|  1 | Sam    |  20 | 2000-01-01 | 123456789@qq.com    | China   |
|  2 | Bob    |  20 | 2000-01-01 | bobbob@gmail.com    | USA     |
|  3 | Steven |  20 | 2000-01-01 | steven521@gmail.com | UK      |
|  4 | Amy    |  20 | 2000-01-01 | amy20205205@163.com | China   |
|  5 | Eleven |  20 | 2000-01-01 | 11more11@163.com    | China   |
|  6 | Miffy  |  20 | 2000-01-01 | miffy521@126.com    | Japan   |
+----+--------+-----+------------+---------------------+---------+
6 rows in set (0.00 sec)

DATE相关

刚才把表的结构调整了一下,接下来就是真正的DATE部分了。

SQL的DATE比较特殊,其实比如说Java,就专门为JDBC设计了一个继承自java.util.Date类的java.sql.Date类,有关于String、java.util.Date、java.sql.Date的互相转化请看这里

好啦,回到正题。

MySQL支持的DATE类型

先说说MySQL不同的DATE类型吧。
不同数据库产品支持的是不一样的,这里我们只说MySQL的四种类型:

  • YEAR:YYYY or YY
  • DATE:YYYY-MM-DD
  • DATETIME:YYYY-MM-DD HH:MM:SS
  • TIMESTAMP:YYYY-MM-DD HH:MM:SS

在建表的时候,如果选了时间,就要指定四者之一。
我们在后面演示的时候,只用了其中的DATE和DATETIME两种。

MySQL支持的DATE相关函数

函数 功能
NOW() 返回当前的日期和时间
CURDATE() 返回当前的日期
CURTIME() 返回当前的时间
DATE() 返回日期本身 or 日期+时间的日期
EXTRACT() 返回日期或者时间的某一类型,比如月份
DATE_ADD() 返回向后延伸指定时间间隔的时间
DATE_SUB() 返回向前回溯指定时间间隔的时间
DATEDIFF() 返回两个日期之间的天数
DATE_FORMAT() 返回自定义格式的日期和时间

还需要补充一下,EXTRACT()、DATE_ADD()、DATE_SUB()需要指定“对谁动手”,可针对下面的几种“动手”:

  • MICROSECOND
  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • WEEK
  • MONTH
  • QUARTER
  • YEAR
  • SECOND_MICROSECOND
  • MINUTE_MICROSECOND
  • MINUTE_SECOND
  • HOUR_MICROSECOND
  • HOUR_SECOND
  • HOUR_MINUTE
  • DAY_MICROSECOND
  • DAY_SECOND
  • DAY_MINUTE
  • DAY_HOUR
  • YEAR_MONTH

首先是NOW()、CURDATE()、CURTIME()的使用,这个不需要专门查表:

mysql> select now(), curdate(), curtime();
+---------------------+------------+-----------+
| now()               | curdate()  | curtime() |
+---------------------+------------+-----------+
| 2020-03-17 10:41:20 | 2020-03-17 | 10:41:20  |
+---------------------+------------+-----------+
1 row in set (0.36 sec)

比如NOW()吧,其实可以用作DEFAULT约束的呢。

我突然觉得不对啊,这个是不好,我想换成’YYYY-MM-DD HH:MM:SS’格式,于是改了一下:

mysql> update stu_info
    -> set birthday='2000-1-1 12:00:00';
Query OK, 0 rows affected, 6 warnings (0.11 sec)
Rows matched: 6  Changed: 0  Warnings: 6

Warnings: 6 ???
(别急,看下去)
于是我们查一下表,结果还是那样,并没有显示YYYY-MM-DD HH:MM:SS:

mysql> select * from stu_info;
+----+--------+-----+------------+---------------------+---------+
| id | name   | age | birthday   | email               | country |
+----+--------+-----+------------+---------------------+---------+
|  1 | Sam    |  20 | 2000-01-01 | 123456789@qq.com    | China   |
|  2 | Bob    |  20 | 2000-01-01 | bobbob@gmail.com    | USA     |
|  3 | Steven |  20 | 2000-01-01 | steven521@gmail.com | UK      |
|  4 | Amy    |  20 | 2000-01-01 | amy20205205@163.com | China   |
|  5 | Eleven |  20 | 2000-01-01 | 11more11@163.com    | China   |
|  6 | Miffy  |  20 | 2000-01-01 | miffy521@126.com    | Japan   |
+----+--------+-----+------------+---------------------+---------+
6 rows in set (0.00 sec)

那就先凑合着用吧,接下来测一测DATE():

mysql> select id, name, date(birthday)
    -> from stu_info;
+----+--------+----------------+
| id | name   | date(birthday) |
+----+--------+----------------+
|  1 | Sam    | 2000-01-01     |
|  2 | Bob    | 2000-01-01     |
|  3 | Steven | 2000-01-01     |
|  4 | Amy    | 2000-01-01     |
|  5 | Eleven | 2000-01-01     |
|  6 | Miffy  | 2000-01-01     |
+----+--------+----------------+
6 rows in set (0.00 sec)

结果并不意外,因为本来就这样……

接下来可以测一测EXTRACT()了,只查年月日:

mysql> select id, name, extract(year from birthday) as year, extract(month from birthday) as month,
    -> extract(day from birthday) as day
    -> from stu_info;
+----+--------+------+-------+------+
| id | name   | year | month | day  |
+----+--------+------+-------+------+
|  1 | Sam    | 2000 |     1 |    1 |
|  2 | Bob    | 2000 |     1 |    1 |
|  3 | Steven | 2000 |     1 |    1 |
|  4 | Amy    | 2000 |     1 |    1 |
|  5 | Eleven | 2000 |     1 |    1 |
|  6 | Miffy  | 2000 |     1 |    1 |
+----+--------+------+-------+------+
6 rows in set (0.00 sec)

再查查年、月、日、时、分、秒:

mysql> select id, name, extract(year from birthday) as year, extract(month from birthday) as month,
    -> extract(day from birthday) as day, extract(hour from birthday) as hour, extract(minute from birthday) as minute,
    -> extract(second from birthday) as second
    -> from stu_info;
+----+--------+------+-------+------+------+--------+--------+
| id | name   | year | month | day  | hour | minute | second |
+----+--------+------+-------+------+------+--------+--------+
|  1 | Sam    | 2000 |     1 |    1 |    0 |      0 |      0 |
|  2 | Bob    | 2000 |     1 |    1 |    0 |      0 |      0 |
|  3 | Steven | 2000 |     1 |    1 |    0 |      0 |      0 |
|  4 | Amy    | 2000 |     1 |    1 |    0 |      0 |      0 |
|  5 | Eleven | 2000 |     1 |    1 |    0 |      0 |      0 |
|  6 | Miffy  | 2000 |     1 |    1 |    0 |      0 |      0 |
+----+--------+------+-------+------+------+--------+--------+
6 rows in set (0.00 sec)

突然,我们反应过来了,原来是选了DATE的锅啊,那只能换成DATETIME了:

mysql> alter table stu_info
    -> drop column birthday;
Query OK, 0 rows affected (1.36 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table stu_info
    -> add column birthday datetime
    -> not null
    -> default '2000-1-1 13:00:00'
    -> after age;
Query OK, 0 rows affected (1.38 sec)
Records: 0  Duplicates: 0  Warnings: 0

验证一下:

mysql> select * from stu_info;
+----+--------+-----+---------------------+---------------------+---------+
| id | name   | age | birthday            | email               | country |
+----+--------+-----+---------------------+---------------------+---------+
|  1 | Sam    |  20 | 2000-01-01 13:00:00 | 123456789@qq.com    | China   |
|  2 | Bob    |  20 | 2000-01-01 13:00:00 | bobbob@gmail.com    | USA     |
|  3 | Steven |  20 | 2000-01-01 13:00:00 | steven521@gmail.com | UK      |
|  4 | Amy    |  20 | 2000-01-01 13:00:00 | amy20205205@163.com | China   |
|  5 | Eleven |  20 | 2000-01-01 13:00:00 | 11more11@163.com    | China   |
|  6 | Miffy  |  20 | 2000-01-01 13:00:00 | miffy521@126.com    | Japan   |
+----+--------+-----+---------------------+---------------------+---------+
6 rows in set (0.00 sec)

重复一下之前的查询:

mysql> select id, name, extract(year from birthday) as year, extract(month from birthday) as month,
    -> extract(day from birthday) as day, extract(hour from birthday) as hour, extract(minute from birthday) as minute,
    -> extract(second from birthday) as second
    -> from stu_info;
+----+--------+------+-------+------+------+--------+--------+
| id | name   | year | month | day  | hour | minute | second |
+----+--------+------+-------+------+------+--------+--------+
|  1 | Sam    | 2000 |     1 |    1 |    0 |      0 |      0 |
|  2 | Bob    | 2000 |     1 |    1 |    0 |      0 |      0 |
|  3 | Steven | 2000 |     1 |    1 |    0 |      0 |      0 |
|  4 | Amy    | 2000 |     1 |    1 |    0 |      0 |      0 |
|  5 | Eleven | 2000 |     1 |    1 |    0 |      0 |      0 |
|  6 | Miffy  | 2000 |     1 |    1 |    0 |      0 |      0 |
+----+--------+------+-------+------+------+--------+--------+
6 rows in set (0.00 sec)

只查三个属性:

mysql> select id, name, birthday
    -> from stu_info;
+----+--------+---------------------+
| id | name   | birthday            |
+----+--------+---------------------+
|  1 | Sam    | 2000-01-01 13:00:00 |
|  2 | Bob    | 2000-01-01 13:00:00 |
|  3 | Steven | 2000-01-01 13:00:00 |
|  4 | Amy    | 2000-01-01 13:00:00 |
|  5 | Eleven | 2000-01-01 13:00:00 |
|  6 | Miffy  | 2000-01-01 13:00:00 |
+----+--------+---------------------+
6 rows in set (0.00 sec)

对比上面的,这时才能看出DATE()的作用:

mysql> select id, name, date(birthday)
    -> from stu_info;
+----+--------+----------------+
| id | name   | date(birthday) |
+----+--------+----------------+
|  1 | Sam    | 2000-01-01     |
|  2 | Bob    | 2000-01-01     |
|  3 | Steven | 2000-01-01     |
|  4 | Amy    | 2000-01-01     |
|  5 | Eleven | 2000-01-01     |
|  6 | Miffy  | 2000-01-01     |
+----+--------+----------------+
6 rows in set (0.00 sec)

但我们还想要数据多样化一些,所以改一下年龄和生日:

mysql> update stu_info
    -> set age='21', birthday='1999-5-4 8:00:00'
    -> where id=1;
Query OK, 1 row affected (0.42 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update stu_info
    -> set age='35', birthday='1985-12-3 9:34:20'
    -> where id=2;
Query OK, 1 row affected (0.39 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update stu_info
    -> set age='25', birthday='1995-3-3 6:17:30'
    -> where id=3;
Query OK, 1 row affected (0.39 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update stu_info
    -> set age='19', birthday='2001-7-2 21:30:00'
    -> where id=5;
Query OK, 1 row affected (0.39 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update stu_info
    -> set age='20', birthday='2000-8-10 12:00:00'
    -> where id=6;
Query OK, 1 row affected (0.15 sec)
Rows matched: 1  Changed: 1  Warnings: 0

重新查询,带上一个ORDER BY,注意DATETIME的升序排列其实是age的降序排列

mysql> select id, name, age, birthday
    -> from stu_info
    -> order by birthday;
+----+--------+-----+---------------------+
| id | name   | age | birthday            |
+----+--------+-----+---------------------+
|  2 | Bob    |  35 | 1985-12-03 09:34:20 |
|  3 | Steven |  25 | 1995-03-03 06:17:30 |
|  1 | Sam    |  21 | 1999-05-04 08:00:00 |
|  4 | Amy    |  20 | 2000-01-01 13:00:00 |
|  6 | Miffy  |  20 | 2000-08-10 12:00:00 |
|  5 | Eleven |  19 | 2001-07-02 21:30:00 |
+----+--------+-----+---------------------+
6 rows in set (0.00 sec)

我们可以使用>对birthday做一下筛选,但结果并不好:

mysql> select id, name, age, birthday
    -> from stu_info
    -> where birthday>'2000-01-01 00:00:00'
    -> order by birthday;
+----+--------+-----+---------------------+
| id | name   | age | birthday            |
+----+--------+-----+---------------------+
|  4 | Amy    |  20 | 2000-01-01 13:00:00 |
|  6 | Miffy  |  20 | 2000-08-10 12:00:00 |
|  5 | Eleven |  19 | 2001-07-02 21:30:00 |
+----+--------+-----+---------------------+
3 rows in set (0.35 sec)

上面这个时间的排序可能不那么令我们满意,因为取大于就应该取到上界,但反而得到了下界,这个不好,所以使用<更自然些:

mysql> select id, name, age, birthday
    -> from stu_info
    -> where birthday<'2000-01-01 00:00:00'
    -> order by birthday;
+----+--------+-----+---------------------+
| id | name   | age | birthday            |
+----+--------+-----+---------------------+
|  2 | Bob    |  35 | 1985-12-03 09:34:20 |
|  3 | Steven |  25 | 1995-03-03 06:17:30 |
|  1 | Sam    |  21 | 1999-05-04 08:00:00 |
+----+--------+-----+---------------------+
3 rows in set (0.00 sec)

再测测DATE_ADD(),它可以在指定时间上附加一段时间:

mysql> select id, name, age, date_add(birthday, interval 10 year) as ten_years_old
    -> from stu_info;
+----+--------+-----+---------------------+
| id | name   | age | ten_years_old       |
+----+--------+-----+---------------------+
|  1 | Sam    |  21 | 2009-05-04 08:00:00 |
|  2 | Bob    |  35 | 1995-12-03 09:34:20 |
|  3 | Steven |  25 | 2005-03-03 06:17:30 |
|  4 | Amy    |  20 | 2010-01-01 13:00:00 |
|  5 | Eleven |  19 | 2011-07-02 21:30:00 |
|  6 | Miffy  |  20 | 2010-08-10 12:00:00 |
+----+--------+-----+---------------------+
6 rows in set (0.36 sec)

不只是能加整数,还能加负数(相当于减):

mysql> select id, name, age, date_add(birthday, interval -10 year) as ten_years_before
    -> from stu_info;
+----+--------+-----+---------------------+
| id | name   | age | ten_years_before    |
+----+--------+-----+---------------------+
|  1 | Sam    |  21 | 1989-05-04 08:00:00 |
|  2 | Bob    |  35 | 1975-12-03 09:34:20 |
|  3 | Steven |  25 | 1985-03-03 06:17:30 |
|  4 | Amy    |  20 | 1990-01-01 13:00:00 |
|  5 | Eleven |  19 | 1991-07-02 21:30:00 |
|  6 | Miffy  |  20 | 1990-08-10 12:00:00 |
+----+--------+-----+---------------------+
6 rows in set (0.36 sec)

有DATE_ADD(),自然有DATE_SUB():

mysql> select id, name, age, date_sub(birthday, interval -10 year) as ten_years_old
    -> from stu_info;
+----+--------+-----+---------------------+
| id | name   | age | ten_years_old       |
+----+--------+-----+---------------------+
|  1 | Sam    |  21 | 2009-05-04 08:00:00 |
|  2 | Bob    |  35 | 1995-12-03 09:34:20 |
|  3 | Steven |  25 | 2005-03-03 06:17:30 |
|  4 | Amy    |  20 | 2010-01-01 13:00:00 |
|  5 | Eleven |  19 | 2011-07-02 21:30:00 |
|  6 | Miffy  |  20 | 2010-08-10 12:00:00 |
+----+--------+-----+---------------------+
6 rows in set (0.00 sec)

DATE_DIFF()也可一测,求的是两个时间之差:

mysql> select i1.name, i2.name, datediff(date(i1.birthday), date(i2.birthday))as diff
    -> from stu_info i1, stu_info i2;
+--------+--------+-------+
| name   | name   | diff  |
+--------+--------+-------+
| Sam    | Sam    |     0 |
| Bob    | Sam    | -4900 |
| Steven | Sam    | -1523 |
| Amy    | Sam    |   242 |
| Eleven | Sam    |   790 |
| Miffy  | Sam    |   464 |
| Sam    | Bob    |  4900 |
| Bob    | Bob    |     0 |
| Steven | Bob    |  3377 |
| Amy    | Bob    |  5142 |
| Eleven | Bob    |  5690 |
| Miffy  | Bob    |  5364 |
| Sam    | Steven |  1523 |
| Bob    | Steven | -3377 |
| Steven | Steven |     0 |
| Amy    | Steven |  1765 |
| Eleven | Steven |  2313 |
| Miffy  | Steven |  1987 |
| Sam    | Amy    |  -242 |
| Bob    | Amy    | -5142 |
| Steven | Amy    | -1765 |
| Amy    | Amy    |     0 |
| Eleven | Amy    |   548 |
| Miffy  | Amy    |   222 |
| Sam    | Eleven |  -790 |
| Bob    | Eleven | -5690 |
| Steven | Eleven | -2313 |
| Amy    | Eleven |  -548 |
| Eleven | Eleven |     0 |
| Miffy  | Eleven |  -326 |
| Sam    | Miffy  |  -464 |
| Bob    | Miffy  | -5364 |
| Steven | Miffy  | -1987 |
| Amy    | Miffy  |  -222 |
| Eleven | Miffy  |   326 |
| Miffy  | Miffy  |     0 |
+--------+--------+-------+
36 rows in set (0.38 sec)

最后试试格式化,即DATE_FORMAT()。

下面列举了一些主要的格式化符号:

格式符 表示的意义
%a 缩写星期名
%b 缩写月名
%c 月,数值
%D 带有英文前缀的月中的天
%d 月的天,数值(00-31)
%e 月的天,数值(0-31)
%f 微秒
%H 小时(00-23)
%h 小时(01-12)
%I 小时(01-12)
%i 分钟,数值(00-59)
%j 年的天(001-366)
%k 小时(0-23)
%l 小时(1-12)
%M 月名
%m 月,数值(00-12)
%p AM 或 PM
%r 时间,12-小时(hh:mm:ss AM 或 PM)
%S 秒(00-59)
%s 秒(00-59)
%T 时间, 24-小时(hh:mm:ss)
%U 周(00-53)星期日是一周的第一天
%u 周(00-53)星期一是一周的第一天
%V 周(01-53)星期日是一周的第一天,与 %X 使用
%v 周(01-53)星期一是一周的第一天,与 %x 使用
%W 星期名
%w 周的天(0=星期日, 6=星期六)
%X 年,其中的星期日是周的第一天,4 位,与 %V 使用
%x 年,其中的星期一是周的第一天,4 位,与 %v 使用
%Y 年,4 位
%y 年,2 位

那我们就组合一下DATE()与DATE_FORMAT()吧:

mysql> select date_format(now(), '%b%d %Y') as format;
+------------+
| format     |
+------------+
| Mar17 2020 |
+------------+
1 row in set (0.00 sec)

完美退出

mysql> \q
Bye

总结

讲了这么多,有语法,有排坑点拨,也有实战演练,不知道大家看完之后可有收获?
写了这么久,希望得到大家的支持!谢谢!

Next Step

《基于MySQL的SQL核心语法实战演练(三)》

发布了725 篇原创文章 · 获赞 1548 · 访问量 72万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104919171
今日推荐