1 行分类
你可能已经在前面的例子中注意到,结果行的显示没有特定的顺序。当结果行以某种有意义的方式进行排序时,检查查询输出通常会更容易。要对结果进行排序,请使用ORDER BY子句。
以下是按日期排序的动物生日:
mysql> SELECT name, birth FROM pet ORDER BY birth;+----------+------------+| name     | birth      |+----------+------------+| Buffy    | 1989-05-13 || Bowser   | 1989-08-31 || Fang     | 1990-08-27 || Fluffy   | 1993-02-04 || Claws    | 1994-03-17 || Slim     | 1996-04-29 || Whistler | 1997-12-09 || Chirpy   | 1998-09-11 || Puffball | 1999-03-30 |+----------+------------+在字符类型的列上,排序——像所有其他比较操作一样——通常是以不区分大小写的方式执行的。这意味着,除了大小写之外完全相同的列的顺序是未定义的。你可以通过使用BINARY来强制对列进行区分大小写的排序,如下所示:ORDER BY BINARY col_name。
默认的排序顺序是升序,即最小的值排在最前面。为了按相反的顺序(降序)排序,可以在你正在排序的列名后添加DESC关键字:
mysql> SELECT name, birth FROM pet ORDER BY birth DESC;+----------+------------+| name     | birth      |+----------+------------+| Puffball | 1999-03-30 || Chirpy   | 1998-09-11 || Whistler | 1997-12-09 || Slim     | 1996-04-29 || Claws    | 1994-03-17 || Fluffy   | 1993-02-04 || Fang     | 1990-08-27 || Bowser   | 1989-08-31 || Buffy    | 1989-05-13 |+----------+------------+你可以按多个列进行排序,并且可以为不同的列指定不同的排序方向。例如,要按照动物类型以升序排序,然后在每种动物类型内按出生日期以降序排序(最年轻的动物排在最前面),可以使用以下查询:
mysql> SELECT name, species, birth FROM petORDER BY species, birth DESC;+----------+---------+------------+| name     | species | birth      |+----------+---------+------------+| Chirpy   | bird    | 1998-09-11 || Whistler | bird    | 1997-12-09 || Claws    | cat     | 1994-03-17 || Fluffy   | cat     | 1993-02-04 || Fang     | dog     | 1990-08-27 || Bowser   | dog     | 1989-08-31 || Buffy    | dog     | 1989-05-13 || Puffball | hamster | 1999-03-30 || Slim     | snake   | 1996-04-29 |+----------+---------+------------+DESC关键字仅适用于它紧前面的列名(在此例中是birth);它不会影响其他列(如species)的排序顺序。
2 日期计算
MySQL提供了几个函数,你可以使用它们来对日期进行计算,例如计算年龄或提取日期的部分信息。
为了确定你的每只宠物的年龄,你可以使用TIMESTAMPDIFF()函数。该函数的参数包括你希望结果以什么单位表示,以及要计算差异的两个日期。以下查询显示了每只宠物的出生日期、当前日期和以年为单位的年龄。使用别名(age)来使最终输出列的标签更有意义。
mysql> SELECT name, birth, CURDATE(),TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS ageFROM pet;+----------+------------+------------+------+| name     | birth      | CURDATE()  | age  |+----------+------------+------------+------+| Fluffy   | 1993-02-04 | 2003-08-19 |   10 || Claws    | 1994-03-17 | 2003-08-19 |    9 || Buffy    | 1989-05-13 | 2003-08-19 |   14 || Fang     | 1990-08-27 | 2003-08-19 |   12 || Bowser   | 1989-08-31 | 2003-08-19 |   13 || Chirpy   | 1998-09-11 | 2003-08-19 |    4 || Whistler | 1997-12-09 | 2003-08-19 |    5 || Slim     | 1996-04-29 | 2003-08-19 |    7 || Puffball | 1999-03-30 | 2003-08-19 |    4 |+----------+------------+------------+------+查询是有效的,但如果按某种顺序排列行,结果会更容易扫描。这可以通过添加一个ORDER BY name子句来按名称对输出进行排序来实现:
mysql> SELECT name, birth, CURDATE(),TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS ageFROM pet ORDER BY name;+----------+------------+------------+------+| name     | birth      | CURDATE()  | age  |+----------+------------+------------+------+| Bowser   | 1989-08-31 | 2003-08-19 |   13 || Buffy    | 1989-05-13 | 2003-08-19 |   14 || Chirpy   | 1998-09-11 | 2003-08-19 |    4 || Claws    | 1994-03-17 | 2003-08-19 |    9 || Fang     | 1990-08-27 | 2003-08-19 |   12 || Fluffy   | 1993-02-04 | 2003-08-19 |   10 || Puffball | 1999-03-30 | 2003-08-19 |    4 || Slim     | 1996-04-29 | 2003-08-19 |    7 || Whistler | 1997-12-09 | 2003-08-19 |    5 |+----------+------------+------------+------+要按照年龄而不是名称对输出进行排序,只需使用不同的ORDER BY子句:
mysql> SELECT name, birth, CURDATE(),TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS ageFROM pet ORDER BY age;+----------+------------+------------+------+| name     | birth      | CURDATE()  | age  |+----------+------------+------------+------+| Chirpy   | 1998-09-11 | 2003-08-19 |    4 || Puffball | 1999-03-30 | 2003-08-19 |    4 || Whistler | 1997-12-09 | 2003-08-19 |    5 || Slim     | 1996-04-29 | 2003-08-19 |    7 || Claws    | 1994-03-17 | 2003-08-19 |    9 || Fluffy   | 1993-02-04 | 2003-08-19 |   10 || Fang     | 1990-08-27 | 2003-08-19 |   12 || Bowser   | 1989-08-31 | 2003-08-19 |   13 || Buffy    | 1989-05-13 | 2003-08-19 |   14 |+----------+------------+------------+------+一个类似的查询可以用来确定已经死亡的动物的死亡年龄。你可以通过检查death值是否为NULL来确定哪些动物已经死亡。然后,对于那些具有非NULL值的动物,计算death和birth值之间的差异:
mysql> SELECT name, birth, death,TIMESTAMPDIFF(YEAR,birth,death) AS ageFROM pet WHERE death IS NOT NULL ORDER BY age;+--------+------------+------------+------+| name   | birth      | death      | age  |+--------+------------+------------+------+| Bowser | 1989-08-31 | 1995-07-29 |    5 |+--------+------------+------------+------+查询中使用 death IS NOT NULL 而不是 death <> NULL,因为 NULL 是一个特殊值,不能使用常规的比较运算符进行比较。
如果你想知道哪些动物下个月过生日怎么办?对于这类计算,年份和日期是无关紧要的;你只想提取birth列的月份部分。MySQL提供了几个用于提取日期部分的函数,如YEAR()、MONTH()和DAYOFMONTH()。在这里,MONTH()是合适的函数。为了看看它是如何工作的,运行一个简单的查询,显示birth和MONTH(birth)的值:
mysql> SELECT name, birth, MONTH(birth) FROM pet;+----------+------------+--------------+| name     | birth      | MONTH(birth) |+----------+------------+--------------+| Fluffy   | 1993-02-04 |            2 || Claws    | 1994-03-17 |            3 || Buffy    | 1989-05-13 |            5 || Fang     | 1990-08-27 |            8 || Bowser   | 1989-08-31 |            8 || Chirpy   | 1998-09-11 |            9 || Whistler | 1997-12-09 |           12 || Slim     | 1996-04-29 |            4 || Puffball | 1999-03-30 |            3 |+----------+------------+--------------+要找出下个月过生日的动物也很简单。假设当前是4月,那么月份值是4,你可以像这样寻找5月(5月)出生的动物:
mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;+-------+------------+| name  | birth      |+-------+------------+| Buffy | 1989-05-13 |+-------+------------+如果当前月份是12月,就会有一点小复杂。你不能仅仅将月份数字(12)加一来寻找13月出生的动物,因为没有这样的月份。相反,你要寻找的是1月(1月)出生的动物。
你可以编写查询,使其无论当前月份是什么都能工作,这样你就不必使用特定月份的数字了。DATE_ADD() 允许你在给定的日期上添加一个时间间隔。如果你在 CURDATE() 的值上加一个月,然后用 MONTH() 提取月份部分,结果就会产生要寻找生日的月份:
mysql> SELECT name, birth FROM petWHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));您提到的方法是一种有效的解决方案,它使用模运算(MOD)来处理从12月到1月的过渡。下面是一个具体的SQL查询示例,该查询将找到下个月过生日的宠物,无论当前月份是什么:
mysql> SELECT name, birth FROM petWHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;MONTH() 函数返回 1 到 12 之间的数字,而 MOD(something, 12) 返回 0 到 11 之间的数字。因此,加法运算必须在 MOD() 函数之后进行,以确保结果仍然在 1 到 12 的范围内。这样可以避免从 11 月(11)直接跳到 1 月(1)的情况。
关于无效日期的计算,确实,如果在进行日期计算时使用了无效的日期或时间值,MySQL 可能会产生警告或错误。这通常发生在尝试创建不存在的日期(如 2 月 30 日)或超出日期范围的值时。
mysql> SELECT '2018-10-31' + INTERVAL 1 DAY;+-------------------------------+| '2018-10-31' + INTERVAL 1 DAY |+-------------------------------+| 2018-11-01                    |+-------------------------------+mysql> SELECT '2018-10-32' + INTERVAL 1 DAY;+-------------------------------+| '2018-10-32' + INTERVAL 1 DAY |+-------------------------------+| NULL                          |+-------------------------------+mysql> SHOW WARNINGS;+---------+------+----------------------------------------+| Level   | Code | Message                                |+---------+------+----------------------------------------+| Warning | 1292 | Incorrect datetime value: '2018-10-32' |+---------+------+----------------------------------------+