注意:本文操作全部在终端进行
数据库(database)是保存有组织的数据的容器(通常是一个文件或一组文件),实质上数据库是一个以某种 有组织的方式存储的数据集合,数据库软件应称为DBMS(数据库管理系统)。数据库是通过DBMS创建和操纵的容器
表(table) 某种特定类型数据的结构化清单。存储在表中的数据是一种类型的数据或一个清单,数据库中的每个表都有一个名字,用来标识自己。此名字是唯一的, 这表示数据库中没有其他表具有相同的名字。说白了就是通过表来建立起数据的索引关系,如果将一本书比作数据库,那么表就是像目录一样的东西
注意:虽然在相同数据库中不能两次使用相同的表名, 但在不同的数据库中却可以使用相同的表名
模式(schema) 关于数据库和表的布局及特性的信息。表具有一些特性,这些特性定义了数据在表中如何存储,如可以存储什么样的数据,数据如何分解,各部分信息如何命名等等。描述表的这组信息就是所谓的模式,模式可以用来描述数据库中特定的表以及整个数据库和其中表的关系
表由列组成。列中存储着表中某部分的信息。 列(column) 是表中的一个字段。所有表都是由一个或多个列组成的,还是拿书本举例,如果说表是目录,那么每个列就是一组具有某一共同特征的一单元
数据库中每个列都有相应的数据类型。数据类型定义列可以存储的数据种类,数据类型(datatype) 所容许的数据的类型。每个表列都有相 应的数据类型,它限制(或容许)该列中存储的数据。
表中的数据是按行存储的,所保存的每个记录存储在自己的行内。 如果将表想象为网格,网格中垂直的列为表列,水平行为表行。
表中每一行都应该有可以唯一标识自己的一列(或一组列)。表中的任何列都可以作为主键,只要它满足以下条件:
SQL(Structured Query Language)是一种专门用于管理关系型数据库系统的编程语言。它允许用户执行各种任务,包括数据查询、数据插入、数据更新、数据删除以及数据库模式的创建和修改:
mysql -h 主机名 -u 用户名 -p # -p表示在接下来输入数据库的用户密码
\g
作为结束标志,直接回车将会换行help
或\h
获取帮助#
或--
加上一个空格SHOW DATABASES;
SELECT VERSION();
USE 数据库名; # 选定数据库
SHOW TABLES; # 获取当前数据库中所有表名
上述两句也可以合并为:
SHOW 数据库名.TABLES;
SHOW COLUMNS FROM 表名;
SHOW COLUMNS FROM 数据库名.表名;
在MySQL中还有一种方式:
DESCRIBE 表名;
MySQL支持用DESCRIBE
作为SHOW COLUMNS FROM
的一种快捷方式
SELECT 字段名 FROM 表名; # 注意这种方式不会对数据进行排序
下面是测试演示:
mysql> SELECT username FROM phptest.user;
+---------------+
| username |
+---------------+
| john_doe |
| jane_smith |
| alice_johnson |
+---------------+
3 rows in set (0.00 sec)
SELECT 字段名1, 字段名2 ... FROM 表名;
下面是测试演示:
mysql> SELECT username, email FROM phptest.user;
+---------------+-------------------+
| username | email |
+---------------+-------------------+
| john_doe | john@example.com |
| jane_smith | jane@example.com |
| alice_johnson | alice@example.com |
+---------------+-------------------+
3 rows in set (0.00 sec)
SELECT * FROM 表名;
mysql> SELECT * FROM phptest.user;
+----+---------------+-------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+-------------+-------------------+---------------------+
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
+----+---------------+-------------+-------------------+---------------------+
3 rows in set (0.00 sec)
先提前插入两行重复数据
mysql> SELECT DISTINCT * FROM phptest.user;
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+---------------+--------------+-------------------+---------------------+
5 rows in set (0.01 sec)
然后我们使用DISTINCT
进行降重
SELECT DISTINCT 字段名 FROM 表名;
下面是演示示例:
mysql> SELECT DISTINCT username FROM phptest.user;
+---------------+
| username |
+---------------+
| john_doe |
| jane_smith |
| alice_johnson |
| doge |
+---------------+
4 rows in set (0.00 sec)
注意:DISTINCT关键字,它必须直接放在列名的前面
SELECT 字段名 FROM 表名 LIMIT n;
SELECT 字段名 FROM 表名 LIMIT n,m;
注意:行的起始位置的标记是0,即第一个limit的第一个参数可视为数组下标,第二个为返回行数(如果只使用了一个参数,则直接从0开始返回结果)
如果说指定返回的函数超过了表中的总行数,将只返回表中的仅有的行数
演示执行结果:
mysql> SELECT DISTINCT username FROM phptest.user LIMIT 1,2;
+---------------+
| username |
+---------------+
| jane_smith |
| alice_johnson |
+---------------+
2 rows in set (0.00 sec)
记得前文的 SELECT DISTINCT username FROM phptest.user;
吗?这种语法叫做完全限定即限制访问的表来自phptest
,同样字段名也可以进行限制:
mysql> SELECT user.username FROM phptest.user;
+---------------+
| username |
+---------------+
| john_doe |
| jane_smith |
| alice_johnson |
| doge |
| doge |
+---------------+
5 rows in set (0.00 sec)
注意:检索出的数据并不是以纯粹的随机顺序显示的。如果不排 序,数据一般将以它在底层表中出现的顺序显示。这可以是数据最初,添加到表中的顺序。但是,如果数据后来进行过更新或删除,则此顺 序将会受到MySQL重用回收存储空间的影响。因此,如果不明确控 制的话,不能(也不应该)依赖该排序顺序。关系数据库设计理论认 为,如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有意义 --------by 《MySQL必知必会》
先介绍子句的概念:
子句(clause) SQL语句由子句构成,有些子句是必需的,而有的是可选的。一个子句通常由一个关键字和所提供的数据组 成。子句的例子有SELECT语句的FROM子句
我们使用order by
来对其进行排序,其基本格式为:
SELECT ... FROM ... ORDER BY 字段名
例如我们以email
字段来排序,将会得到以下结果,可见下方的排序是以email
字段的内容首字母排序的
mysql> SELECT * FROM phptest.user order by email;
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
+----+---------------+--------------+-------------------+---------------------+
5 rows in set (0.00 sec)
SELECT ... FROM ... ORDER BY 字段名1, 字段名2 ...
我们可以在order by的后面跟上多个字段,在查询时将会先以字段1进行排序,然后再根据字段2依次进行排序:
mysql> SELECT * FROM phptest.user order by password,email;
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
+----+---------------+--------------+-------------------+---------------------+
5 rows in set (0.00 sec)
我们可以在order by
后面的字段名跟上DESC
关键字进行降序排列
mysql> SELECT * FROM phptest.user ORDER BY id DESC, username;
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
+----+---------------+--------------+-------------------+---------------------+
5 rows in set (0.01 sec)
与DESC相反的关键字是ASC(ASCENDING),在升序排序时可以指定它。 但实际上,ASC没有多大用处,因为升序是默认的(如果既不指定ASC也 不指定DESC,则假定为ASC)
在SELECT语句中,数据根据WHERE子句中指定的搜索条件进行过滤。 WHERE子句在表名(FROM子句)之后给出
mysql> SELECT * FROM phptest.user WHERE username="doge";
+----+----------+--------------+------------------+---------------------+
| id | username | password | email | registration_date |
+----+----------+--------------+------------------+---------------------+
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+----------+--------------+------------------+---------------------+
2 rows in set (0.00 sec)
此外WHERE子句还可以使用条件匹配,下面是常见的操作符:
运算 | 示例 |
---|---|
大于 | 1>2 |
小于 | 1<2 |
大于等于 | 4>=3 |
小于等于 | 3<=2 |
不等于 | 5<>5 |
不等于 | 5!=5 |
兼容空值等于 | 3<=>4 |
在 … 与 … 之间 | between 1 and 6 |
mysql> SELECT * FROM phptest.user WHERE id BETWEEN 2 AND 5;
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+---------------+--------------+-------------------+---------------------+
4 rows in set (0.00 sec)
NULL 无值(no value),它与字段包含0、空字符串或仅仅包含 空格不同,在创建表时,表设计人员可以指定其中的列是否可以不包含值。在 一个列不包含值时,称其为包含空值NULL,MySQL自带一个判断空值的关键字:
SELECT ... FROM ... WHERE ... IS NULL;
mysql> SELECT * FROM phptest.user WHERE id<5 AND id>2;
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
+----+---------------+--------------+-------------------+---------------------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM phptest.user WHERE id>4 OR id<2;
+----+----------+--------------+------------------+---------------------+
| id | username | password | email | registration_date |
+----+----------+--------------+------------------+---------------------+
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+----------+--------------+------------------+---------------------+
2 rows in set (0.00 sec)
在SQL语句中允许对AND
和OR
进行组合,但是AND
的运算优先级高于OR
,如下面的例子:
mysql> SELECT * FROM phptest.user WHERE id=2 OR id>4 AND username="doge";
+----+------------+--------------+------------------+---------------------+
| id | username | password | email | registration_date |
+----+------------+--------------+------------------+---------------------+
| 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+------------+--------------+------------------+---------------------+
2 rows in set (0.00 sec)
解决方法是使用括号进行优先级划分:
mysql> SELECT * FROM phptest.user WHERE (id=2 OR id>4) AND username="doge";
+----+----------+--------------+------------------+---------------------+
| id | username | password | email | registration_date |
+----+----------+--------------+------------------+---------------------+
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+----------+--------------+------------------+---------------------+
1 row in set (0.00 sec)
IN WHERE子句中用来指定要匹配值的清单的关键字,功能与OR 相当。IN操作符后跟由逗号分隔的合法值清单,整个清单必须括在圆括号中。
mysql> SELECT * FROM phptest.user WHERE id IN (1,3,5);
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+---------------+--------------+-------------------+---------------------+
3 rows in set (0.00 sec)
需要注意的是,它是一个列表指定,并非是m~n
的这样一个范围
IN关键字相比与OR子句的优越性
NOT WHERE子句中用来否定后跟条件的关键字
mysql> SELECT * FROM phptest.user WHERE id NOT IN (1,2,5);
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
+----+---------------+--------------+-------------------+---------------------+
2 rows in set (0.00 sec)
通配符(wildcard) 用来匹配值的一部分的特殊字符
搜索模式(search pattern)由字面值、通配符或两者组合构成的搜索条件
%
匹配任何字段出现任何次mysql> select * from user where username like 'do%';
+----+----------+--------------+------------------+---------------------+
| id | username | password | email | registration_date |
+----+----------+--------------+------------------+---------------------+
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+----------+--------------+------------------+---------------------+
2 rows in set (0.00 sec)
_
匹配任何字数出现单次mysql> select * from user where username like 'd_';
Empty set (0.00 sec)
mysql> select * from user where username like 'd_ge';
+----+----------+--------------+------------------+---------------------+
| id | username | password | email | registration_date |
+----+----------+--------------+------------------+---------------------+
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+----------+--------------+------------------+---------------------+
2 rows in set (0.00 sec)
mysql> select * from user where username regexp '.O.';
+----+---------------+--------------+-------------------+---------------------+
| id | username | password | email | registration_date |
+----+---------------+--------------+-------------------+---------------------+
| 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 |
| 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 |
| 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 |
| 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 |
+----+---------------+--------------+-------------------+---------------------+
4 rows in set (0.00 sec)
注意:MySQL中的正则表达式匹配(自版本 3.23.4后)不区分大小写(即,大写和小写都匹配)。为区分大 小写,可使用BINARY关键字
mysql> select * from user where username regexp binary '.O.';
Empty set (0.00 sec)
故名思意,计算自段是DBMS计算出来的,它并不存在于数据库中,无法被客户机所引用,例如concat创建的字段:
mysql> select concat(username," ", email) from user where username regexp '.o.';
+----------------------------------+
| concat(username," ", email) |
+----------------------------------+
| john_doe john@example.com |
| alice_johnson alice@example.com |
| doge doge@example.com |
| doge doge@example.com |
+----------------------------------+
4 rows in set (0.00 sec)
如果要使用该字段,可以使用as建立别名:
mysql> select concat(username," ", email)as kunkun_fan from user where username regexp '.o.';
+----------------------------------+
| kunkun_fan |
+----------------------------------+
| john_doe john@example.com |
| alice_johnson alice@example.com |
| doge doge@example.com |
| doge doge@example.com |
+----------------------------------+
4 rows in set (0.00 sec)
mysql> select id,username,(id *100)as ikun_value from user;
+----+---------------+------------+
| id | username | ikun_value |
+----+---------------+------------+
| 1 | john_doe | 100 |
| 2 | jane_smith | 200 |
| 3 | alice_johnson | 300 |
| 4 | doge | 400 |
| 5 | doge | 500 |
+----+---------------+------------+
5 rows in set (0.00 sec)
别名的常见的用途包括在实际 的表列名包含不符合规定的字符(如空格)时重新命名它,在 原来的名字含混或容易误解时扩充它
先添加一行测试的数据:
mysql> select * from phptest.user; +----+---------------+--------------+-----------------------+---------------------+ | id | username | password | email | registration_date | +----+---------------+--------------+-----------------------+---------------------+ | 5 | doge | passwd123456 | doge@example.com | 2023-10-25 21:26:00 | | 4 | doge | passwd123456 | doge@example.com | 2023-10-25 21:25:47 | | 3 | alice_johnson | mypassword | alice@example.com | 2023-10-19 18:43:23 | | 2 | jane_smith | securepass | jane@example.com | 2023-10-19 18:43:23 | | 1 | john_doe | password123 | john@example.com | 2023-10-19 18:43:23 | | 6 | test test | passwd123 | test_test@example.com | 2023-10-26 21:26:00 | +----+---------------+--------------+-----------------------+---------------------+ 6 rows in set (0.00 sec)
mysql> select Upper(username) from phptest.user where id=6;
+-----------------+
| Upper(username) |
+-----------------+
| TEST TEST |
+-----------------+
1 row in set (0.00 sec)
select Lower(username) from phptest.user where id=6;
mysql> select Rtrim(username) from phptest.user where id=6;
+-----------------+
| Rtrim(username) |
+-----------------+
| test test |
+-----------------+
1 row in set (0.00 sec)
mysql> select Ltrim(username) from phptest.user where id=6;
+-----------------+
| Ltrim(username) |
+-----------------+
| test test |
+-----------------+
1 row in set (0.00 sec)
常见的字符串处理函数表格
函数 | 描述 |
---|---|
CONCAT(str1, str2, …) | 连接两个或多个字符串。 |
CONCAT_WS(separator, str1, str2, …) | 使用指定的分隔符连接字符串。 |
SUBSTRING(str, start, length) | 从字符串中提取子串,起始位置为start,长度为length。 |
LEFT(str, length) | 从字符串的左边截取指定长度的字符。 |
RIGHT(str, length) | 从字符串的右边截取指定长度的字符。 |
LENGTH(str) | 返回字符串的长度。 |
CHAR_LENGTH(str) | 返回字符串的字符数。 |
LOWER(str) | 将字符串转换为小写。 |
UPPER(str) | 将字符串转换为大写。 |
TRIM([LEADING | TRAILING | BOTH] trim_character FROM str) | 去除字符串首部、尾部或两端指定字符。 |
REPLACE(str, from_str, to_str) | 替换字符串中的子字符串。 |
REVERSE(str) | 反转字符串。 |
LOCATE(substr, str[, start]) | 返回子字符串在字符串中第一次出现的位置。 |
INSERT(str, start, length, new_str) | 在字符串中插入新的子串。 |
FORMAT(number, decimal_places) | 将数字格式化为带有指定小数位数的字符串。 |
函数 | 描述 |
---|---|
NOW() | 返回当前日期和时间。 |
CURDATE() | 返回当前日期。 |
CURTIME() | 返回当前时间。 |
DATE_FORMAT(date, format) | 格式化日期。 |
EXTRACT(unit FROM date) | 从日期中提取指定的单元(例如,年、月、日、时、分等)。 |
DATE_ADD(date, INTERVAL expr unit) | 在日期上加上指定的时间间隔。 |
DATE_SUB(date, INTERVAL expr unit) | 从日期中减去指定的时间间隔。 |
DATEDIFF(end_date, start_date) | 计算两个日期之间的天数差。 |
TIMESTAMPDIFF(unit, start_datetime, end_datetime) | 计算两个日期或时间之间的差异,单位可以是秒、分钟、小时等。 |
STR_TO_DATE(str, format) | 将字符串转换为日期。 |
DATE(str) | 将字符串转换为日期。 |
TIME(str) | 将字符串转换为时间。 |
YEAR(date) | 提取日期的年份。 |
MONTH(date) | 提取日期的月份。 |
DAY(date) | 提取日期的日。 |
HOUR(time) | 提取时间的小时。 |
MINUTE(time) | 提取时间的分钟。 |
SECOND(time) | 提取时间的秒。 |
函数 | 描述 | 示例 |
---|---|---|
ABS(x) | 返回一个数的绝对值。 | SELECT ABS(-10); 结果: 10 |
ROUND(x, d) | 返回一个数按照指定小数位数四舍五入后的值。 | SELECT ROUND(12.345, 1); 结果: 12.3 |
CEIL(x) 或 CEILING(x) | 返回不小于 x 的最小整数。 | SELECT CEIL(12.345); 结果: 13 |
FLOOR(x) | 返回不大于 x 的最大整数。 | SELECT FLOOR(12.345); 结果: 12 |
RAND() | 返回一个 0 到 1 之间的随机浮点数。 | SELECT RAND(); |
SIGN(x) | 返回一个数的正负号。 | SELECT SIGN(-10); 结果: -1 |
SQRT(x) | 返回一个数的平方根。 | SELECT SQRT(25); 结果: 5 |
POWER(x, y) 或 POW(x, y) | 返回 x 的 y 次方。 | SELECT POWER(2, 3); 结果: 8 |
LOG(x) | 返回 x 的自然对数。 | SELECT LOG(10); 结果: 2.302585092994046 |
EXP(x) | 返回 e(自然对数的底)的 x 次方。 | SELECT EXP(2); 结果: 7.3890560989306495 |
数据统计使用的是聚集函数:聚集函数(aggregate function) 运行在行组上,计算和返回单 个值的函数。
函数 | 描述 |
---|---|
COUNT(expr) | 返回结果集中行的数量。可以使用 COUNT(*) 返回所有行的数量。 |
SUM(expr) | 计算表达式的总和。 |
AVG(expr) | 计算表达式的平均值。 |
MIN(expr) | 返回表达式的最小值。 |
MAX(expr) | 返回表达式的最大值。 |
GROUP_CONCAT(expr [ORDER BY sorting_option] [SEPARATOR sep]) | 将组内行的值连接为一个字符串。 |
DISTINCT expr | 返回唯一不同的表达式值的数量。 |
如下示例:
-- 计算员工表中的行数
SELECT COUNT(*) FROM employees;
-- 计算销售表中销售额的总和
SELECT SUM(sales_amount) FROM sales;
-- 计算产品表中价格的平均值
SELECT AVG(price) FROM products;
-- 找到订单表中最早和最晚的订单日期
SELECT MIN(order_date) AS earliest_order, MAX(order_date) AS latest_order FROM orders;
注意:使用聚集函数时,可以使用DISTINCT
保证只统计数据中不重复的字段
mysql> select SUM(price) from phptest.products;
+------------+
| SUM(price) |
+------------+
| 3411.92 |
+------------+
1 row in set (0.00 sec)
mysql> select sum(DISTINCT price) from phptest.products;
+---------------------+
| sum(DISTINCT price) |
+---------------------+
| 2211.92 |
+---------------------+
1 row in set (0.00 sec)
GROUP BY
是 SQL 中的一个子句,用于将具有相同值的指定列的行分组到汇总行中,例如 “总数” 或 “计数”。它通常与聚合函数(如 SUM
、COUNT
、AVG
等)一起使用,以在每个行组上执行操作。需要注意的是在默认的 sql_mode
为 only_full_group_by
的情况下,MySQL 要求在 GROUP BY
中列出的列以外的列都必须使用聚合函数进行处理,以确保查询的结果是唯一的
mysql> select * from testdb.orders;
+----------+-------------+------------+--------------+
| order_id | customer_id | order_date | order_amount |
+----------+-------------+------------+--------------+
| 1 | 1 | 2022-01-01 | 100.50 |
| 2 | 1 | 2022-01-02 | 75.20 |
| 3 | 2 | 2022-01-01 | 150.75 |
| 4 | 2 | 2022-01-03 | 200.00 |
| 5 | 3 | 2022-01-02 | 50.30 |
+----------+-------------+------------+--------------+
5 rows in set (0.00 sec)
mysql> select order_date,sum(order_amount) from testdb.orders group by order_date;
+------------+-------------------+
| order_date | sum(order_amount) |
+------------+-------------------+
| 2022-01-01 | 251.25 |
| 2022-01-02 | 125.50 |
| 2022-01-03 | 200.00 |
+------------+-------------------+
3 rows in set (0.00 sec)
mysql> select order_date,sum(order_amount) as sum from testdb.orders group by order_date having sum >150 ;
+------------+--------+
| order_date | sum |
+------------+--------+
| 2022-01-01 | 251.25 |
| 2022-01-03 | 200.00 |
+------------+--------+
2 rows in set (0.00 sec)
GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套为数据分组提供更细致的控制。如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。
GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。除聚集计算语句外,SELECT语句中的每个列都必须在GROUPBY子句中给出。
如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。GROUP BY子句必须出现在WHERE子之后,ORDER BY子之前。
WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。