MySQL——查询(2)
这篇文章是接着上一篇文章MySQL——查询(1)的续篇,用于查询的数据表在第一篇文章中已经给出了,如果不知道请看一下第一篇文章。
接着讨论mysql的基本查询语句
-- 聚集函数的用法,一般都结合GROUP BY 使用但也可以不和GROUP BY一起使用
-- COUNT(*) 统计一列中元组的个数,也就是记录的条数
-- SUM() 计算一列中值得总和
-- AVG() 计算一列中的平均数
-- MAX() 计算一列值中的最大值
-- MIN() 求列值中的最小值
-- 这是标准SQL中支持的函数,下面介绍一些mysql支持的函数
-- GROUP_CONCAT() 得到分组详情,如下列子
-- 查询id,sex,用户名详情按照性别分组
SELECT id,sex,GROUP_CONCAT(username) FROM cms_user GROUP BY sex;
+----+--------+---------------------------------+
| id | sex | GROUP_CONCAT(username) |
+----+--------+---------------------------------+
| 1 | 男 | 张三,rose,king,ring,章子怡 |
| 4 | 女 | long,queen,blek,张三丰,lily |
| 11 | 保密 | john,test1 |
+----+--------+---------------------------------+
-- 我们怎么理解这个函数的功能呢?可以先看一下这个查询
SELECT username FROM cms_user;
+-----------+
| username |
+-----------+
| blek |
| john |
| king |
| lily |
| long |
| queen |
| ring |
| rose |
| test1 |
| 张三 |
| 张三丰 |
| 章子怡 |
+-----------+
-- 然后再使用group_concat函数
SELECT GROUP_CONCAT(username) FROM cms_user;
+---------------------------------------------------------------------------+
| GROUP_CONCAT(username) |
+---------------------------------------------------------------------------+
| blek,john,king,lily,long,queen,ring,rose,test1,张三,张三丰,章子怡 |
+---------------------------------------------------------------------------+
-- 这样就把username的内容输出结果集合在一起,然后再用group by语句。
SELECT GROUP_CONCAT(username) FROM cms_user group by sex;
+---------------------------------+
| GROUP_CONCAT(username) |
+---------------------------------+
| 张三,rose,king,ring,章子怡 |
| long,queen,blek,张三丰,lily |
| john,test1 |
+---------------------------------+
SELECT id,GROUP_CONCAT(username) FROM cms_user where id >= 5 group by sex;
+----+------------------------+
| id | GROUP_CONCAT(username) |
+----+------------------------+
| 5 | ring,king,rose |
| 6 | queen,blek,lily |
| 11 | john,test1 |
+----+------------------------+
-- 我们可以这样理解,先根据sex分成不同的组,每个组里面都有很多记录,然后用group_concat函数把这些每个组里面的username连接起来
-- 这里还要注意的是group_concat函数 不会去重
SELECT proId,GROUP_CONCAT(sex) FROM cms_user GROUP BY proId;
+-------+------------------------+
| proId | GROUP_CONCAT(sex) |
+-------+------------------------+
| 1 | 男,女,保密 |
| 2 | 男,女,男,女,保密 |
| 3 | 女,男 |
| 4 | 女 |
| 5 | 男 |
+-------+------------------------+
-- 更新一下cms_user 表中的年龄
UPDATE cms_user SET age=11 WHERE id=1;
UPDATE cms_user SET age=21 WHERE id=2;
UPDATE cms_user SET age=33 WHERE id=3;
UPDATE cms_user SET age=44 WHERE id=4;
UPDATE cms_user SET age=25 WHERE id=5;
UPDATE cms_user SET age=77 WHERE id=6;
UPDATE cms_user SET age=56 WHERE id=7;
UPDATE cms_user SET age=88 WHERE id=8;
UPDATE cms_user SET age=12 WHERE id=9;
UPDATE cms_user SET age=32 WHERE id=10;
UPDATE cms_user SET age=65 WHERE id=11;
--查询编号,sex,用户名详情以及组中总人数按照sex分组
SELECT id,sex,GROUP_CONCAT(username)AS users,COUNT(*) AS totalUsers FROM cms_user GROUP BY sex;
----+--------+---------------------------------+------------+
| id | sex | users | totalUsers |
+----+--------+---------------------------------+------------+
| 1 | 男 | 张三,rose,king,ring,章子怡 | 5 |
| 4 | 女 | long,queen,blek,张三丰,lily | 5 |
| 11 | 保密 | john,test1 | 2 |
+----+--------+---------------------------------+------------+
select id,username from cms_user where id>=5;
+----+----------+
| id | username |
+----+----------+
| 5 | ring |
| 6 | queen |
| 7 | king |
| 8 | blek |
| 9 | rose |
| 10 | lily |
| 11 | john |
| 12 | test1 |
+----+----------+
-- 接着查询id号>=5的用户有多少个
select count(*) from cms_user where id>=5;
+----------+
| count(*) |
+----------+
| 8 |
+----------+
select count(username) from cms_user where id>=5;
+-----------------+
| count(username) |
+-----------------+
| 8 |
+-----------------+
-- 也可以重命名,在count后面的参数可以是具体的字段,也可以是*通配符
select count(username) totalUser from cms_user where id>=5;
+-----------+
| totalUser |
+-----------+
| 8 |
+-----------+
-- 注意:COUNT(字段)不统计NULL值
SELECT COUNT(age) AS totalUsers FROM cms_user;
+------------+
| totalUsers |
+------------+
| 11 |
+------------+
--查询编号,性别,用户名详情,组中总人数,组中最大年龄,最小年龄,
-- 平均年龄,以及年龄总和按照性别分组
SELECT id,sex,GROUP_CONCAT(username),
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
MIN(age) AS min_age,
AVG(age) AS avg_age,
SUM(age) AS sum_age
FROM cms_user
GROUP BY sex;
+----+--------+---------------------------------+------------+---------+---------+---------+---------+
| id | sex | GROUP_CONCAT(username) | totalUsers | max_age | min_age | avg_age | sum_age |
+----+--------+---------------------------------+------------+---------+---------+---------+---------+
| 1 | 男 | 张三,rose,king,ring,章子怡 | 5 | 56 | 11 | 27.4000 | 137 |
| 4 | 女 | long,queen,blek,张三丰,lily | 5 | 88 | 21 | 52.4000 | 262 |
| 11 | 保密 | john,test1 | 2 | 65 | 65 | 65.0000 | 65 |
+----+--------+---------------------------------+------------+---------+---------+---------+---------+
-- WITH ROLLUP用法详解,
-- 首先观察下面的这个查询出来的结果
SELECT id,sex,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
MIN(age) AS min_age
FROM cms_user
GROUP BY sex;
+----+--------+------------+---------+---------+
| id | sex | totalUsers | max_age | min_age |
+----+--------+------------+---------+---------+
| 1 | 男 | 5 | 56 | 11 |
| 2 | 女 | 5 | 88 | 21 |
| 11 | 保密 | 2 | 65 | 65 |
+----+--------+------------+---------+---------+
-- 然后再看如下的查询与上面查询的区别在哪里
SELECT id,sex,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
MIN(age) AS min_age
FROM cms_user
GROUP BY sex WITH ROLLUP;
| id | sex | totalUsers | max_age | min_age |
+----+--------+------------+---------+---------+
| 1 | 男 | 5 | 56 | 11 |
| 4 | 女 | 5 | 88 | 21 |
| 11 | 保密 | 2 | 65 | 65 |
| 11 | NULL | 12 | 88 | 11 |
+----+--------+------------+---------+---------+
-- 这里我解释解释WITH ROLLUP的功能
-- 首先with rollup会在查询的结果的最后加上一条记录,看第一列为id,第一列上没有使用聚集函数所以就直接在最后填充的记录上变为原来记录的最后一条复制过去,这里就是11然后因为这里是以sex分组,所以赋值为NULL,在第三列中使用了count函数,在这里就是直接把输出在屏幕上的值5 5 2 使用count函数加起来赋值就为12,第四列就使用了max函数,这里就在输出的结果中使用max函数找出56 88 65 中的最大值88 赋值过去,最后一列使用了min函数,这里也使用min找出11 21 65 中的最小值赋值过去
-- 接下来再看这样的一个查询
SELECT id,sex,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
MIN(age) AS min_age,
proid
FROM cms_user
GROUP BY proid WITH ROLLUP;
+----+------+------------+---------+---------+-------+
| id | sex | totalUsers | max_age | min_age | proid |
+----+------+------------+---------+---------+-------+
| 1 | 男 | 3 | 88 | 11 | 1 |
| 5 | 男 | 5 | 65 | 12 | 2 |
| 6 | 女 | 2 | 77 | 33 | 3 |
| 4 | 女 | 1 | 44 | 44 | 4 |
| 7 | 男 | 1 | 56 | 56 | 5 |
| 7 | 男 | 12 | 88 | 11 | NULL |
+----+------+------------+---------+---------+-------+
-- 再对照上一个查询比较一下这两个查询的不同和相同之处 体会一下with rollup
-- having字句用法
--查询性别sex,用户名详情,组中总人数,最大年龄,年龄总和,根据性别分组
SELECT sex,GROUP_CONCAT(username) AS users,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
SUM(age) AS sum_age
FROM cms_user
GROUP BY sex;
+--------+---------------------------------+------------+---------+---------+
| sex | users | totalUsers | max_age | sum_age |
+--------+---------------------------------+------------+---------+---------+
| 男 | 张三,rose,king,ring,章子怡 | 5 | 56 | 137 |
| 女 | long,queen,blek,张三丰,lily | 5 | 88 | 262 |
| 保密 | john,test1 | 2 | 65 | 65 |
+--------+---------------------------------+------------+---------+---------+
-- 查询组中总人数大于2的,对分组结果的二次筛选,having位置放在group by 之后
SELECT sex,GROUP_CONCAT(username) AS users,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
SUM(age) AS sum_age
FROM cms_user
GROUP BY sex
HAVING COUNT(*)>2;
+------+---------------------------------+------------+---------+---------+
| sex | users | totalUsers | max_age | sum_age |
+------+---------------------------------+------------+---------+---------+
| 男 | 张三,rose,king,ring,章子怡 | 5 | 56 | 137 |
| 女 | long,queen,blek,张三丰,lily | 5 | 88 | 262 |
+------+---------------------------------+------------+---------+---------+
-- 查询组中人数大于2并且最大年龄大于60的
SELECT sex,GROUP_CONCAT(username) AS users,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
SUM(age) AS sum_age
FROM cms_user
GROUP BY sex
HAVING COUNT(*)>2 AND MAX(age)>60;
+------+--------------------------------+------------+---------+---------+
| sex | users | totalUsers | max_age | sum_age |
+------+--------------------------------+------------+---------+---------+
| 女 | long,queen,blek,张三丰,lily | 5 | 88 | 262 |
+------+--------------------------------+------------+---------+---------+
-- 查询编号大于等于2的用户
SELECT sex,GROUP_CONCAT(username) AS users,
COUNT(*) AS totalUsers,
MAX(age) AS max_age,
SUM(age) AS sum_age
FROM cms_user
WHERE id>=6
GROUP BY sex
HAVING COUNT(*)>2 AND MAX(age)>60;
+------+-----------------+------------+---------+---------+
| sex | users | totalUsers | max_age | sum_age |
+------+-----------------+------------+---------+---------+
| 女 | queen,blek,lily | 3 | 88 | 197 |
+------+-----------------+------------+---------+---------+
-- 接下来我们总结下where 和 having的区别,可以这样简单的理解,where的作用对象是表,而having作用对象是 已经查询出来的结果也就是说先查询出很多的记录再在查询出的结果上筛选
-- 具体看一看一下查询语句
select id iddd,username user from cms_user having iddd>3;
+------+-------+
| iddd | user |
+------+-------+
| 8 | blek |
| 11 | john |
| 7 | king |
| 10 | lily |
| 4 | long |
| 6 | queen |
| 5 | ring |
| 9 | rose |
| 12 | test1 |
+------+-------+
select id iddd,username user from cms_user where iddd>3;
+------+-------+
| iddd | user |
+------+-------+
| 8 | blek |
| 11 | john |
| 7 | king |
| 10 | lily |
| 4 | long |
| 6 | queen |
| 5 | ring |
| 9 | rose |
| 12 | test1 |
+------+-------+
-- 这两个查询都是可以的,因为用select id iddd,username user from cms_user 查询出来的结果都有id列
select id iddd,username user from cms_user having id>3;
+------+-------+
| iddd | user |
+------+-------+
| 8 | blek |
| 11 | john |
| 7 | king |
| 10 | lily |
| 4 | long |
| 6 | queen |
| 5 | ring |
| 9 | rose |
| 12 | test1 |
+------+-------+
-- 再继续查看如下的查询
select id iddd,username user from cms_user where proid>3;
+------+------+
| iddd | user |
+------+------+
| 4 | long |
| 7 | king |
+------+------+
select id iddd,username user from cms_user having proid>3;
ERROR 1054 (42S22): Unknown column 'proid' in 'having clause'
-- 不知道 having从句中的proid列 这是因为在select id iddd,username user from cms_user查询出来的结果中没有包含 proid 列,如果在前面添加上proid列也会查询成功
select id iddd,username user,proid from cms_user having proid>3;
+------+------+-------+
| iddd | user | proid |
+------+------+-------+
| 4 | long | 4 |
| 7 | king | 5 |
+------+------+-------+
-- 总结having和where不同就在于先后的关系,where比having先。
-- 还有一点区别就是where后面不能接聚集函数,但是having可以
select id iddd,username user,proid,count(*) from cms_user having count(*)>3;
+------+--------+-------+----------+
| iddd | user | proid | count(*) |
+------+--------+-------+----------+
| 1 | 张三 | 1 | 12 |
+------+--------+-------+----------+
-- 如果where后面接聚集函数会直接报错
select id iddd,username user,proid,count(*) from cms_user where count(*)>3;
ERROR 1111 (HY000): Invalid use of group function
-- order by 排序语句
-- 按照id降序排列DESC 默认的是ASC
SELECT id,username,password FROM cms_user ORDER BY id ;
+----+-----------+--------------+
| id | username | password |
+----+-----------+--------------+
| 1 | 张三 | zhangsan |
| 2 | 张三丰 | zhangsanfeng |
| 3 | 章子怡 | zhangsan |
| 4 | long | long |
| 5 | ring | ring |
| 6 | queen | queen |
| 7 | king | king |
| 8 | blek | blek |
| 9 | rose | rose |
| 10 | lily | lily |
| 11 | john | john |
| 12 | test1 | test1 |
+----+-----------+--------------+
SELECT id,username,password FROM cms_user ORDER BY id DESC;
+----+-----------+--------------+
| id | username | password |
+----+-----------+--------------+
| 12 | test1 | test1 |
| 11 | john | john |
| 10 | lily | lily |
| 9 | rose | rose |
| 8 | blek | blek |
| 7 | king | king |
| 6 | queen | queen |
| 5 | ring | ring |
| 4 | long | long |
| 3 | 章子怡 | zhangsan |
| 2 | 张三丰 | zhangsanfeng |
| 1 | 张三 | zhangsan |
+----+-----------+--------------+
-- 按照年龄升序排列
SELECT username,age FROM cms_user ORDER BY age ASC;
+-----------+------+
| username | age |
+-----------+------+
| test1 | NULL |
| 张三 | 11 |
| rose | 12 |
| 张三丰 | 21 |
| ring | 25 |
| lily | 32 |
| 章子怡 | 33 |
| long | 44 |
| king | 56 |
| john | 65 |
| queen | 77 |
| blek | 88 |
+-----------+------+
-- 这里应该注意的是在order by 排序中也是和having一样是在查询出的结果集中进行排序可以查看下面的查询语句
SELECT age,id FROM cms_user ORDER BY 1;
+------+----+
| age | id |
+------+----+
| NULL | 12 |
| 11 | 1 |
| 12 | 9 |
| 21 | 2 |
| 25 | 5 |
| 32 | 10 |
| 33 | 3 |
| 44 | 4 |
| 56 | 7 |
| 65 | 11 |
| 77 | 6 |
| 88 | 8 |
+------+----+
SELECT age,id FROM cms_user ORDER BY 2;
+------+----+
| age | id |
+------+----+
| 11 | 1 |
| 21 | 2 |
| 33 | 3 |
| 44 | 4 |
| 25 | 5 |
| 77 | 6 |
| 56 | 7 |
| 88 | 8 |
| 12 | 9 |
| 32 | 10 |
| 65 | 11 |
| NULL | 12 |
+------+----+
SELECT age,id FROM cms_user ORDER BY id;
+------+----+
| age | id |
+------+----+
| 11 | 1 |
| 21 | 2 |
| 33 | 3 |
| 44 | 4 |
| 25 | 5 |
| 77 | 6 |
| 56 | 7 |
| 88 | 8 |
| 12 | 9 |
| 32 | 10 |
| 65 | 11 |
| NULL | 12 |
+------+----+
SELECT age,id FROM cms_user ORDER BY 3;
ERROR 1054 (42S22): Unknown column '3' in 'order clause'
-- 但是我们不用数字指定列,直接用字段名称也行
SELECT age,id FROM cms_user ORDER BY proid;
+------+----+
| age | id |
+------+----+
| 11 | 1 |
| 88 | 8 |
| NULL | 12 |
| 25 | 5 |
| 21 | 2 |
| 12 | 9 |
| 32 | 10 |
| 65 | 11 |
| 77 | 6 |
| 33 | 3 |
| 44 | 4 |
| 56 | 7 |
+------+----+
-- 所以我们用数字指定排序对象的时候应该特别注意
UPDATE cms_user SET age=12 WHERE id=5;
-- 按照年龄升序,id降序排列
SELECT age,id FROM cms_user ORDER BY age ASC,id DESC;
+------+----+
| age | id |
+------+----+
| NULL | 12 |
| 11 | 1 |
| 12 | 9 |
| 12 | 5 |
| 21 | 2 |
| 32 | 10 |
| 33 | 3 |
| 44 | 4 |
| 56 | 7 |
| 65 | 11 |
| 77 | 6 |
| 88 | 8 |
+------+----+
-- 排序也可以按照先后顺序 如果出现相同的age则又根据id降序排列 也阔以按照三个或者以上的字段排序
-- 实现记录随机
SELECT * FROM cms_user ORDER BY RAND();
+----+-----------+--------------+-------------+------------+----------+-------+------+--------+
| id | username | password | email | regTime | face | proId | age | sex |
+----+-----------+--------------+-------------+------------+----------+-------+------+--------+
| 6 | queen | queen | user@qq.com | 1419861708 | user.jpg | 3 | 77 | 女 |
| 12 | test1 | test1 | user@qq.com | 1419811708 | user.jpg | 1 | NULL | 保密 |
| 9 | rose | rose | user@qq.com | 1419821708 | user.jpg | 2 | 12 | 男 |
| 4 | long | long | user@qq.com | 1419814708 | user.jpg | 4 | 44 | 女 |
| 10 | lily | lily | user@qq.com | 1419831708 | user.jpg | 2 | 32 | 女 |
| 8 | blek | blek | user@qq.com | 1419818708 | user.jpg | 1 | 88 | 女 |
| 2 | 张三丰 | zhangsanfeng | user@qq.com | 1419812708 | user.jpg | 2 | 21 | 女 |
| 7 | king | king | user@qq.com | 1419817708 | user.jpg | 5 | 56 | 男 |
| 1 | 张三 | zhangsan | user@qq.com | 1419811708 | user.jpg | 1 | 11 | 男 |
| 5 | ring | ring | user@qq.com | 1419815708 | user.jpg | 2 | 12 | 男 |
| 11 | john | john | user@qq.com | 1419841708 | user.jpg | 2 | 65 | 保密 |
| 3 | 章子怡 | zhangsan | user@qq.com | 1419813708 | user.jpg | 3 | 33 | 男 |
+----+-----------+--------------+-------------+------------+----------+-------+------+--------+
-- 每次执行都是返回的不一样的查询结果
-- limit 关键字限制显示条数,格式: LIMIT [offset,] rows | rows OFFSET offset
-- 显示表中的所有记录
select id,username,password from cms_user;
+----+-----------+--------------+
| id | username | password |
+----+-----------+--------------+
| 1 | 张三 | zhangsan |
| 2 | 张三丰 | zhangsanfeng |
| 3 | 章子怡 | zhangsan |
| 4 | long | long |
| 5 | ring | ring |
| 6 | queen | queen |
| 7 | king | king |
| 8 | blek | blek |
| 9 | rose | rose |
| 10 | lily | lily |
| 11 | john | john |
| 12 | test1 | test1 |
+----+-----------+--------------+
-- 显示查询结果中的前3条记录
SELECT id,username,password FROM cms_user LIMIT 3;
+----+-----------+--------------+
| id | username | password |
+----+-----------+--------------+
| 1 | 张三 | zhangsan |
| 2 | 张三丰 | zhangsanfeng |
| 3 | 章子怡 | zhangsan |
+----+-----------+--------------+
-- 显示id号最大的五条记录
SELECT id,username,password FROM cms_user ORDER BY id DESC LIMIT 5;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 12 | test1 | test1 |
| 11 | john | john |
| 10 | lily | lily |
| 9 | rose | rose |
| 8 | blek | blek |
+----+----------+----------+
-- 查询表中前一条记录
-- LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量(说得通俗易懂点就是从第几条记录开始计数),第二个参数指定返回记录行的最大数目(也就是返回从第一个参数标记的位置开始,向后返回记录的条数,具体的列子可以参考如下)。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。
SELECT id,username,password FROM cms_user LIMIT 0,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | 张三 | zhangsan |
+----+----------+----------+
-- 查询从第二行
SELECT id,password,username FROM cms_user LIMIT 1,1;
+----+--------------+-----------+
| id | password | username |
+----+--------------+-----------+
| 2 | zhangsanfeng | 张三丰 |
+----+--------------+-----------+
SELECT id,password,username FROM cms_user LIMIT 1,2;
+----+--------------+-----------+
| id | password | username |
+----+--------------+-----------+
| 2 | zhangsanfeng | 张三丰 |
| 3 | zhangsan | 章子怡 |
+----+--------------+-----------+
-- OFFSET的用法就相当于把逗号换成OFFSET关键字,把这两个参数的位置交换一下
SELECT id,password,username FROM cms_user LIMIT 1 OFFSET 1;
+----+--------------+-----------+
| id | password | username |
+----+--------------+-----------+
| 2 | zhangsanfeng | 张三丰 |
+----+--------------+-----------+
SELECT id,password,username FROM cms_user LIMIT 2 OFFSET 1;
+----+--------------+-----------+
| id | password | username |
+----+--------------+-----------+
| 2 | zhangsanfeng | 张三丰 |
| 3 | zhangsan | 章子怡 |
+----+--------------+-----------+
SELECT id,password,username FROM cms_user LIMIT 1 OFFSET 2;
+----+----------+-----------+
| id | password | username |
+----+----------+-----------+
| 3 | zhangsan | 章子怡 |
+----+----------+-----------+
-- 最后我就是要总结下这么多的查询语句到底执行的顺序是什么样子的,结果看如下截图