MySQL 基础(四)
进阶 5 分组查询
语法:
SELECT 分组函数, 列(要求出现在 group by 的后面)
FROM 表
[where 筛选条件]
group by 分组的列表
[order by 子句]
注意: 查询列表必须特殊, 要求是分组函数的和 group by 后出现的字段
特点:
1, 分组查询中的筛选条件分为两类
数据源 位置 关键字
分组前筛选 原始表 GROUP BY 子句的前面 WHERE
分组后筛选 分组后的语句集 GROUP BY 子句的后面 HAVING
一, 分组函数做条件肯定是放在 Having 子句中
二, 能用分组前筛选的, 就优先考虑使用分组筛选
2,GROUP BY 子句支持单个字段分组, 也支持多个字段分组
(多个字段之间用逗号分开没有排序要求), 表达式或函数(用的较少)
3, 也可以添加排序(排序放在整个分组查询的最后)
# 引入案例: 查询每个部门的平均工资
SELECT department_id 部门 id, AVG(salary) 平均工资 FROM employees GROUP BY department_id;
- # 简单分组查询
- # 案例一: 查询每个工种的最高工资
SELECT MAX(salary) 最高工资, job_id 工种 FROM employees GROUP BY job_id;
# 案例二: 查询每个位置上的部门个数
SELECT COUNT(*) 部门个数, location_id 位置 id FROM departments GROUP BY location_id;
- # 添加分组前筛选条件
- # 案例 1: 查询邮箱中包含 a 字符的, 每个部门平均工资
- SELECT AVG(salary),department_id
- FROM employees WHERE email LIKE '%a%'
- GROUP BY department_id
- # 案例二: 查询有奖金的每个领导手下员工的最高工资
- SELECT MAX(salary),manager_id FROM employees
- WHERE commission_pct IS NOT NULL
- GROUP BY manager_id;
- # 添加分组后的筛选
- # 案例 1: 查询那个部门的员工个数 > 2
SELECT department_id 部门 id,COUNT(*) 个数 FROM employees
- GROUP BY department_id
- HAVING COUNT(*)>2 ;
- # 案例二: 查询每个工种有奖金的员工的最该工资> 12000 的工种编号和最高工资
- SELECT MAX(salary),job_id FROM employees
- WHERE commission_pct IS NOT NULL
- GROUP BY job_id
- HAVING MAX(salary)> 12000;
- # 按表达式或函数分组
- # 案例: 按员工姓名的长度分组, 查询每一组员工个数, 筛选员工个数> 5 的有哪些
- SELECT COUNT(*),LENGTH(last_name) len_name
- FROM employees
- GROUP BY LENGTH(last_name)
- HAVING COUNT(*)> 5;
- # 按多个字段分组
- # 案例: 查询每个部门每个工种的员工的平均工资
- SELECT AVG(salary),department_id,job_id FROM employees
- GROUP BY department_id ,job_id;
- # 添加排序
- ## 案例: 查询每个部门每个工种的员工的平均工资, 并且平均工资的高低显示
- SELECT AVG(salary),department_id,job_id FROM employees
- GROUP BY department_id ,job_id
- ORDER BY AVG(salary) DESC;
进阶 6 连接查询
添加测试数据库:
- /*
- SQLyog Ultimate v10.00 Beta1
- MySQL - 5.7.18-log : Database - girls
- *********************************************************************
- */
- /*!40101 SET NAMES utf8 */;
- /*!40101 SET SQL_MODE=''*/;
- /*!40014 SET @[email protected]@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
- /*!40014 SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
- /*!40101 SET @[email protected]@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
- /*!40111 SET @[email protected]@SQL_NOTES, SQL_NOTES=0 */;
- CREATE DATABASE /*!32312 IF NOT EXISTS*/`girls` /*!40100 DEFAULT CHARACTER SET utf8 */;
- USE `girls`;
- /*Table structure for table `admin` */
- DROP TABLE IF EXISTS `admin`;
- CREATE TABLE `admin` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `username` varchar(10) NOT NULL,
- `password` varchar(10) NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
- /*Data for the table `admin` */
- insert into `admin`(`id`,`username`,`password`) values (1,'john','8888'),(2,'lyt','6666');
- /*Table structure for table `beauty` */
- DROP TABLE IF EXISTS `beauty`;
- CREATE TABLE `beauty` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(50) NOT NULL,
- `sex` char(1) DEFAULT '女',
- `borndate` datetime DEFAULT '1987-01-01 00:00:00',
- `phone` varchar(11) NOT NULL,
- `photo` blob,
- `boyfriend_id` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
- /*Data for the table `beauty` */
- insert into `beauty`(`id`,`name`,`sex`,`borndate`,`phone`,`photo`,`boyfriend_id`) values (1,'柳岩','女','1988-02-03 00:00:00','18209876577',NULL,8),(2,'苍老师','女','1987-12-30 00:00:00','18219876577',NULL,9),(3,'Angelababy','女','1989-02-03 00:00:00','18209876567',NULL,3),(4,'热巴','女','1993-02-03 00:00:00','18209876579',NULL,2),(5,'周冬雨','女','1992-02-03 00:00:00','18209179577',NULL,9),(6,'周芷若','女','1988-02-03 00:00:00','18209876577',NULL,1),(7,'岳灵珊','女','1987-12-30 00:00:00','18219876577',NULL,9),(8,'小昭','女','1989-02-03 00:00:00','18209876567',NULL,1),(9,'双儿','女','1993-02-03 00:00:00','18209876579',NULL,9),(10,'王语嫣','女','1992-02-03 00:00:00','18209179577',NULL,4),(11,'夏雪','女','1993-02-03 00:00:00','18209876579',NULL,9),(12,'赵敏','女','1992-02-03 00:00:00','18209179577',NULL,1);
- /*Table structure for table `boys` */
- DROP TABLE IF EXISTS `boys`;
- CREATE TABLE `boys` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `boyName` varchar(20) DEFAULT NULL,
- `userCP` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
- /*Data for the table `boys` */
- insert into `boys`(`id`,`boyName`,`userCP`) values (1,'张无忌',100),(2,'鹿晗',800),(3,'黄晓明',50),(4,'段誉',300);
- /*!40101 SET [email protected]_SQL_MODE */;
- /*!40014 SET [email protected]_FOREIGN_KEY_CHECKS */;
- /*!40014 SET [email protected]_UNIQUE_CHECKS */;
- /*!40111 SET [email protected]_SQL_NOTES */;
- # 连接查询
- /*
- 含义: 又称为多表查询, 当查询的字段来自于多个表时, 就会用到连接查询
- 笛卡尔积现象: 表 1 有 m 行, 表 2 有 n 行, 结果有 m*n 行
- 发生原因: 没有有效的链接条件
- 如何避免: 添加有效的链接条件
- 分类:
- 按年代分类(在 MySQL 中的支持):
- sql92 标准 : 仅仅支持内连接
- sql99 标准[推荐] 支持内连接 + 外连接(左外, 右外)+ 交叉连接
- 按功能分类:
- 内连接:
- 等值连接
- 非等值连接
- 自连接
- 外连接:
- 左外连接
- 右外连接
- 全外连接
- 交叉连接
- */
- # 一: sql92 标准
- #1, 等值连接:
- /*
- 一: 多表等值连接的结果为多表的交集部分
- 二: m 表连接, 至少 n-1 个连接条件
- 三: 多表的顺序没有要求
- 四: 一般需要为表起别名
- 五: 可以搭配前面介绍的所有子句使用, 比如排序, 分组, 筛选
- */
- # 案例 1: 查询女生名很对应的男生名
- SELECT name ,boyName FROM beauty,boys
- WHERE beauty.boyfriend_id=boys.id;
- USE myemployees;
- # 案例 2: 查询员工名和对应的部门名
- SELECT last_name,department_name
- FROM employees,departments
- WHERE employees.department_id = departments.department_id;
- #2, 为表起别名
- /*
- 1, 提高语句的简介度
- 2, 区分多个从重名字段
- 注意: 如果为表起了别名, 则查询的字段就不能使用原来的表名
- */
- # 案例: 查询员工名, 工种号, 工种名
- SELECT last_name,e.job_id,job_title
- FROM employees e,jobs j
- WHERE e.`job_id`=j.`job_id`;
- #3, 两个表的顺序是否可以调换
- SELECT e.last_name,e.job_id,j.job_title
- FROM jobs j,employees e
- WHERE e.`job_id`=j.`job_id`;
- #4, 可以加筛选
- # 案例: 查询有奖金的员工名, 部门名
- SELECT last_name,department_name
- FROM employees e,departments d
- WHERE e.department_id = d.department_id
- AND e.commission_pct IS NOT NULL;
- # 案例 2: 查询城市名中第二个字符为 o 的部门
- SELECT department_name,city
- FROM departments d,locations l
- WHERE d.location_id=l.location_id
- AND city LIKE '_o%';
- #5, 可以加分组
- # 案例: 查询每个城市的部门个数
SELECT COUNT(*) 个数, city
- FROM employees d,locations l
- GROUP BY city;
- # 案例二: 查询有奖金的的每个部门名和部门领导的编号和该部门的最低工资
- SELECT department_name,d.manager_id,MIN(salary) FROM departments d,employees e
- WHERE d.department_id= e.department_id
- AND commission_pct IS NOT NULL
- GROUP BY department_name,d.manager_id;
- #6, 可以加排序
- SELECT job_title,COUNT(*) FROM employees e,jobs j
- WHERE e.job_id = j.job_id
- GROUP BY job_title
- ORDER BY COUNT(*) DESC;
- #7, 可以实现三表连接:
- # 案例: 查询员工名, 部门名和所在城市
- SELECT last_name ,department_name,city
- FROM employees e,departments d,locations l
- WHERE e.department_id = d.department_id
- AND d.location_id = l.location_id
- ORDER BY d.department_name DESC;
来源: http://www.bubuko.com/infodetail-3416253.html