- 一 介绍
- 二 插入数据INSERT
- 三 更新数据UPDATE
- 四 删除数据DELETE
- 五 查询数据SELECT
- 创建表
- 查看表结构
- 插入记录
- 三个部门:教学,销售,运营
- ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk
- 1:单条件查询
- 2:多条件查询
- 3:关键字BETWEEN AND
- 4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS)
- 5:关键字IN集合查询
- 6:关键字LIKE模糊查询
- 1、首先明确一点:分组发生在where之后,即分组是基于where之后得到的记录而进行的
- 2、分组指的是:将所有记录按照某个相同字段进行归类,比如针对员工信息表的职位分组,或者按照性别进行分组等
- 3、为何要分组呢?
- 4、大前提:
- 强调:聚合函数聚合的是组的内容,若是没有分组,则默认一组
- 题1:
- 题目2:
- 题目3:
- 题目1
- 题目2
- 题目3
- 建表
- 插入数据
- 查看表结构和数据
- 找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果
- department没有204这个部门,因而employee表中关于204这条员工信息没有匹配出来
- 上述sql等同于
- 注意:mysql不支持全外连接 full JOIN
- 强调:mysql可以使用此种方式间接实现全外连接
- 查看结果
- 注意 union与union all的区别:union会去掉相同的纪录
- 查询平均年龄在25岁以上的部门名
- 查看技术部员工姓名
- 查看不足1人的部门名(子查询得到的是有人的部门id)
- 在 SQL 中 ANY 和 SOME 是同义词,SOME 的用法和功能和 ANY 一模一样。
- ANY 和 IN 运算符不同之处1
- ANY和 IN 运算符不同之处2
- 比较运算符:=、!=、>、>=、<、<=、<>
- 查询大于所有人平均年龄的员工名与年龄
- 查询大于部门内平均年龄的员工名、年龄
一 介绍
MySQL数据操作: DML
========================================================
在MySQL管理软件中,可以通过SQL语句中的DML语言来实现数据的操作,包括
- 使用INSERT实现数据的插入
- UPDATE实现数据的更新
- 使用DELETE实现数据的删除
- 使用SELECT查询数据以及。
========================================================
本节内容包括:
插入数据
更新数据
删除数据
查询数据
二 插入数据INSERT
1. 插入完整数据(顺序插入)
语法一:
INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n);
语法二:
INSERT INTO 表名 VALUES (值1,值2,值3…值n);
2. 指定字段插入数据
语法:
INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…);
3. 插入多条记录
语法:
INSERT INTO 表名 VALUES
(值1,值2,值3…值n),
(值1,值2,值3…值n),
(值1,值2,值3…值n);
4. 插入查询结果
语法:
INSERT INTO 表名(字段1,字段2,字段3…字段n)
SELECT (字段1,字段2,字段3…字段n) FROM 表2
WHERE …;
三 更新数据UPDATE
语法:
UPDATE 表名 SET
字段1=值1,
字段2=值2,
WHERE CONDITION;
示例:
UPDATE mysql.user SET password=password(‘123’)
where user=’root’ and host=’localhost’;
四 删除数据DELETE
语法:
DELETE FROM 表名
WHERE CONITION;
示例:
DELETE FROM mysql.user
WHERE password=’’;
练习:
更新MySQL root用户密码为mysql123
删除除从本地登录的root用户以外的所有用户
五 查询数据SELECT
1. 单表查询
1.1 单表查询的语法
SELECT 字段1,字段2... FROM 表名
WHERE 条件
GROUP BY field
HAVING 筛选
ORDER BY field
LIMIT 限制条数
1.2 关键字的执行优先级(重点)
重点中的重点:关键字的执行优先级
from
where
group by
having
select
distinct
order by
limit
1.找到表:from
2.拿着where指定的约束条件,去文件/表中取出一条条记录
3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
4.将分组的结果进行having过滤
5.执行select
6.去重
7.将结果按条件排序:order by
8.限制结果的显示条数
SQL逻辑查询语句执行顺序
1.3.1 SELECT语句关键字的定义顺序
SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>
1.3.2 SELECT语句关键字的执行顺序
(7) SELECT
(8) DISTINCT <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
1.3.3 准备表和数据
新建一个测试数据库TestDB;
create database TestDB;
创建测试表table1和table2;
CREATE TABLE table1
(
customer_id VARCHAR(10) NOT NULL,
city VARCHAR(10) NOT NULL,
PRIMARY KEY(customer_id)
)ENGINE=INNODB DEFAULT CHARSET=UTF8;
CREATE TABLE table2
(
order_id INT NOT NULL auto_increment,
customer_id VARCHAR(10),
PRIMARY KEY(order_id)
)ENGINE=INNODB DEFAULT CHARSET=UTF8;
插入测试数据;
INSERT INTO table1(customer_id,city) VALUES('163','hangzhou');
INSERT INTO table1(customer_id,city) VALUES('9you','shanghai');
INSERT INTO table1(customer_id,city) VALUES('tx','hangzhou');
INSERT INTO table1(customer_id,city) VALUES('baidu','hangzhou');
INSERT INTO table2(customer_id) VALUES('163');
INSERT INTO table2(customer_id) VALUES('163');
INSERT INTO table2(customer_id) VALUES('9you');
INSERT INTO table2(customer_id) VALUES('9you');
INSERT INTO table2(customer_id) VALUES('9you');
INSERT INTO table2(customer_id) VALUES('tx');
INSERT INTO table2(customer_id) VALUES(NULL);
准备工作做完以后,table1和table2看起来应该像下面这样:
mysql> select * from table1;
+-------------+----------+
| customer_id | city |
+-------------+----------+
| 163 | hangzhou |
| 9you | shanghai |
| baidu | hangzhou |
| tx | hangzhou |
+-------------+----------+
4 rows in set (0.00 sec)
mysql> select * from table2;
+----------+-------------+
| order_id | customer_id |
+----------+-------------+
| 1 | 163 |
| 2 | 163 |
| 3 | 9you |
| 4 | 9you |
| 5 | 9you |
| 6 | tx |
| 7 | NULL |
+----------+-------------+
7 rows in set (0.00 sec)
1.3.4 准备SQL逻辑查询测试语句
#查询来自杭州,并且订单数少于2的客户。
SELECT a.customer_id, COUNT(b.order_id) as total_orders
FROM table1 AS a
LEFT JOIN table2 AS b
ON a.customer_id = b.customer_id
WHERE a.city = 'hangzhou'
GROUP BY a.customer_id
HAVING count(b.order_id) < 2
ORDER BY total_orders DESC;
1.3.5 执行顺序分析
在这些SQL语句的执行过程中,都会产生一个虚拟表,用来保存SQL语句的执行结果(这是重点),我现在就来跟踪这个虚拟表的变化,得到最终的查询结果的过程,来分析整个SQL逻辑查询的执行顺序和过程。
执行FROM语句
第一步,执行FROM语句。我们首先需要知道最开始从哪个表开始的,这就是FROM告诉我们的。现在有了
关于什么是笛卡尔积,请自行Google补脑。经过FROM语句对两个表执行笛卡尔积,会得到一个虚拟表,暂且叫VT1(vitual table 1),内容如下:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 9you | shanghai | 1 | 163 |
| baidu | hangzhou | 1 | 163 |
| tx | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 2 | 163 |
| baidu | hangzhou | 2 | 163 |
| tx | hangzhou | 2 | 163 |
| 163 | hangzhou | 3 | 9you |
| 9you | shanghai | 3 | 9you |
| baidu | hangzhou | 3 | 9you |
| tx | hangzhou | 3 | 9you |
| 163 | hangzhou | 4 | 9you |
| 9you | shanghai | 4 | 9you |
| baidu | hangzhou | 4 | 9you |
| tx | hangzhou | 4 | 9you |
| 163 | hangzhou | 5 | 9you |
| 9you | shanghai | 5 | 9you |
| baidu | hangzhou | 5 | 9you |
| tx | hangzhou | 5 | 9you |
| 163 | hangzhou | 6 | tx |
| 9you | shanghai | 6 | tx |
| baidu | hangzhou | 6 | tx |
| tx | hangzhou | 6 | tx |
| 163 | hangzhou | 7 | NULL |
| 9you | shanghai | 7 | NULL |
| baidu | hangzhou | 7 | NULL |
| tx | hangzhou | 7 | NULL |
+-------------+----------+----------+-------------+
总共有28(table1的记录条数 * table2的记录条数)条记录。这就是VT1的结果,接下来的操作就在VT1的基础上进行。
执行ON过滤
执行完笛卡尔积以后,接着就进行ON a.customer_id = b.customer_id
条件过滤,根据ON
中指定的条件,去掉那些不符合条件的数据,得到VT2表,内容如下:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
+-------------+----------+----------+-------------+
VT2就是经过ON
条件筛选以后得到的有用数据,而接下来的操作将在VT2的基础上继续进行。
添加外部行
这一步只有在连接类型为OUTER JOIN
时才发生,如LEFT OUTER JOIN
、RIGHT OUTER JOIN
和FULL OUTER JOIN
。在大多数的时候,我们都是会省略掉OUTER
关键字的,但OUTER
表示的就是外部行的概念。LEFT OUTER JOIN
把左表记为保留表,得到的结果为:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
+-------------+----------+----------+-------------+
RIGHT OUTER JOIN
把右表记为保留表,得到的结果为:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| NULL | NULL | 7 | NULL |
+-------------+----------+----------+-------------+
FULL OUTER JOIN
把左右表都作为保留表,得到的结果为:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
| NULL | NULL | 7 | NULL |
+-------------+----------+----------+-------------+
添加外部行的工作就是在VT2表的基础上添加保留表中被过滤条件过滤掉的数据,非保留表中的数据被赋予NULL值,最后生成虚拟表VT3。
由于我在准备的测试SQL查询逻辑语句中使用的是LEFT JOIN
,过滤掉了以下这条数据:
| baidu | hangzhou | NULL | NULL |
现在就把这条数据添加到VT2表中,得到的VT3表如下:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
+-------------+----------+----------+-------------+
接下来的操作都会在该VT3表上进行。
执行WHERE过滤
对添加外部行得到的VT3进行WHERE过滤,只有符合WHERE a.city = 'hangzhou'
的时候,就会得到以下内容,并存在虚拟表VT4中:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
+-------------+----------+----------+-------------+
但是在使用WHERE子句时,需要注意以下两点:
- 由于数据还没有分组,因此现在还不能在WHERE过滤器中使用
where_condition=MIN(col)
这类对分组统计的过滤; - 由于还没有进行列的选取操作,因此在SELECT中使用列的别名也是不被允许的,如:
SELECT city as c FROM t WHERE c='shanghai';
是不允许出现的。
执行GROUP BY分组GROU BY
子句主要是对使用WHERE
子句得到的虚拟表进行分组操作。我们执行测试语句中的GROUP BY a.customer_id
,就会得到以下内容(默认只显示组内第一条):
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| baidu | hangzhou | NULL | NULL |
| tx | hangzhou | 6 | tx |
+-------------+----------+----------+-------------+
得到的内容会存入虚拟表VT5中,此时,我们就得到了一个VT5虚拟表,接下来的操作都会在该表上完成。
执行HAVING过滤HAVING
子句主要和GROUP BY
子句配合使用,对分组得到的VT5虚拟表进行条件过滤。当我执行测试语句中的HAVING count(b.order_id) < 2
时,将得到以下内容:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| baidu | hangzhou | NULL | NULL |
| tx | hangzhou | 6 | tx |
+-------------+----------+----------+-------------+
这就是虚拟表VT6。
SELECT列表
现在才会执行到SELECT
子句,不要以为SELECT
子句被写在第一行,就是第一个被执行的。
我们执行测试语句中的SELECT a.customer_id, COUNT(b.order_id) as total_orders
,从虚拟表VT6中选择出我们需要的内容。我们将得到以下内容:
+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| baidu | 0 |
| tx | 1 |
+-------------+--------------+
还没有完,这只是虚拟表VT7。
执行DISTINCT子句
如果在查询中指定了DISTINCT
子句,则会创建一张内存临时表(如果内存放不下,就需要存放在硬盘了)。这张临时表的表结构和上一步产生的虚拟表VT7是一样的,不同的是对进行DISTINCT操作的列增加了一个唯一索引,以此来除重复数据。
由于我的测试SQL语句中并没有使用DISTINCT,所以,在该查询中,这一步不会生成一个虚拟表。
执行ORDER BY子句
对虚拟表中的内容按照指定的列进行排序,然后返回一个新的虚拟表,我们执行测试SQL语句中的ORDER BY total_orders DESC
,就会得到以下内容:
+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| tx | 1 |
| baidu | 0 |
+-------------+--------------+
可以看到这是对total_orders列进行降序排列的。上述结果会存储在VT8中。
执行LIMIT子句LIMIT
子句从上一步得到的VT8虚拟表中选出从指定位置开始的指定行数据。对于没有应用ORDER BY的LIMIT子句,得到的结果同样是无序的,所以,很多时候,我们都会看到LIMIT子句会和ORDER BY子句一起使用。
MySQL数据库的LIMIT支持如下形式的选择:
LIMIT n, m
表示从第n条记录开始选择m条记录。而很多开发人员喜欢使用该语句来解决分页问题。对于小数据,使用LIMIT子句没有任何问题,当数据量非常大的时候,使用LIMIT n, m
是非常低效的。因为LIMIT的机制是每次都是从头开始扫描,如果需要从第60万行开始,读取3条数据,就需要先扫描定位到60万行,然后再进行读取,而扫描的过程是一个非常低效的过程。所以,对于大数据处理时,是非常有必要在应用层建立一定的缓存机制(现在的大数据处理,大都使用缓存)
1.3 简单查询
- 准备表和记录
```python
company.employee
员工id id int
姓名 emp_name varchar 性别 sex enum 年龄 age int 入职日期 hire_date date 岗位 post varchar 职位描述 post_comment varchar 薪水 salary double 办公室 office int 部门编号 depart_id int
创建表
create table employee( id int not null unique auto_increment, name varchar(20) not null, sex enum(‘male’,’female’) not null default ‘male’, #大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, #一个部门一个屋子 depart_id int );
查看表结构
mysql> desc employee; +———————+———————————-+———+——-+————-+————————+ | Field | Type | Null | Key | Default | Extra | +———————+———————————-+———+——-+————-+————————+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | sex | enum(‘male’,’female’) | NO | | male | | | age | int(3) unsigned | NO | | 28 | | | hire_date | date | NO | | NULL | | | post | varchar(50) | YES | | NULL | | | post_comment | varchar(100) | YES | | NULL | | | salary | double(15,2) | YES | | NULL | | | office | int(11) | YES | | NULL | | | depart_id | int(11) | YES | | NULL | | +———————+———————————-+———+——-+————-+————————+
插入记录
三个部门:教学,销售,运营
insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values (‘xio’,’male’,18,’20170301’,’teacher’,7300.33,401,1), #以下是教学部 (‘jion’,’male’,78,’20150302’,’teacher’,1000000.31,401,1), (‘wupeiqi’,’male’,81,’20130305’,’teacher’,8300,401,1), (‘yuanhao’,’male’,73,’20140701’,’teacher’,3500,401,1), (‘liwenzhou’,’male’,28,’20121101’,’teacher’,2100,401,1), (‘jingliyang’,’female’,18,’20110211’,’teacher’,9000,401,1), (‘jinxin’,’male’,18,’19000301’,’teacher’,30000,401,1), (‘成龙’,’male’,48,’20101111’,’teacher’,10000,401,1),
(‘歪歪’,’female’,48,’20150311’,’sale’,3000.13,402,2),#以下是销售部门 (‘丫丫’,’female’,38,’20101101’,’sale’,2000.35,402,2), (‘丁丁’,’female’,18,’20110312’,’sale’,1000.37,402,2), (‘星星’,’female’,18,’20160513’,’sale’,3000.29,402,2), (‘格格’,’female’,28,’20170127’,’sale’,4000.33,402,2),
(‘张野’,’male’,28,’20160311’,’operation’,10000.13,403,3), #以下是运营部门 (‘程咬金’,’male’,18,’19970312’,’operation’,20000,403,3), (‘程咬银’,’female’,18,’20130311’,’operation’,19000,403,3), (‘程咬铜’,’male’,18,’20150411’,’operation’,18000,403,3), (‘程咬铁’,’female’,18,’20140512’,’operation’,17000,403,3) ;
ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk
```python
#简单查询
SELECT id,name,sex,age,hire_date,post,post_comment,salary,office,depart_id
FROM employee;
SELECT * FROM employee;
SELECT name,salary FROM employee;
#避免重复DISTINCT
SELECT DISTINCT post FROM employee;
#通过四则运算查询
SELECT name, salary*12 FROM employee;
SELECT name, salary*12 AS Annual_salary FROM employee;
SELECT name, salary*12 Annual_salary FROM employee;
#定义显示格式
CONCAT() 函数用于连接字符串
SELECT CONCAT('姓名: ',name,' 年薪: ', salary*12) AS Annual_salary
FROM employee;
CONCAT_WS() 第一个参数为分隔符
SELECT CONCAT_WS(':',name,salary*12) AS Annual_salary
FROM employee;
结合CASE语句:
SELECT
(
CASE
WHEN NAME = 'xio' THEN
NAME
WHEN NAME = 'jion' THEN
CONCAT(name,'_BIGSB')
ELSE
concat(NAME, 'SB')
END
) as new_name
FROM
emp;
例:
1 查出所有员工的名字,薪资,格式为
<名字:xio> <薪资:3000>
2 查出所有的岗位(去掉重复)
- 3 查出所有员工名字,以及他们的年薪,年薪的字段名为annual_year
select concat('<名字:',name,'> ','<薪资:',salary,'>') from employee;
select distinct depart_id from employee;
select name,salary*12 annual_salary from employee;
1.4 WHERE约束
where字句中可以使用:
1. 比较运算符:> < >= <= <> !=
2. between 80 and 100 值在10到20之间
3. in(80,90,100) 值是10或20或30
4. like ‘egon%’
pattern可以是%或,
%表示任意多字符
表示一个字符
5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not ```python1:单条件查询
SELECT name FROM employeeWHERE post='sale';
2:多条件查询
SELECT name,salary FROM employee
WHERE post='teacher' AND salary>10000;
3:关键字BETWEEN AND
SELECT name,salary FROM employee
WHERE salary BETWEEN 10000 AND 20000;
SELECT name,salary FROM employee
WHERE salary NOT BETWEEN 10000 AND 20000;
4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS)
SELECT name,post_comment FROM employee
WHERE post_comment IS NULL;
SELECT name,post_comment FROM employee
WHERE post_comment IS NOT NULL;
SELECT name,post_comment FROM employee
WHERE post_comment=''; 注意''是空字符串,不是null
ps:
执行
update employee set post_comment='' where id=2;
再用上条查看,就会有结果了
5:关键字IN集合查询
SELECT name,salary FROM employee
WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;
SELECT name,salary FROM employee
WHERE salary IN (3000,3500,4000,9000) ;
SELECT name,salary FROM employee
WHERE salary NOT IN (3000,3500,4000,9000) ;
6:关键字LIKE模糊查询
通配符’%’
SELECT * FROM employee
WHERE name LIKE 'xi%';
通配符’_’
SELECT * FROM employee
WHERE name LIKE 'ji__';
例:
- 1. 查看岗位是teacher的员工姓名、年龄
- 2. 查看岗位是teacher且年龄大于30岁的员工姓名、年龄
- 3. 查看岗位是teacher且薪资在9000-1000范围内的员工姓名、年龄、薪资
- 4. 查看岗位描述不为NULL的员工信息
- 5. 查看岗位是teacher且薪资是10000或9000或30000的员工姓名、年龄、薪资
- 6. 查看岗位是teacher且薪资不是10000或9000或30000的员工姓名、年龄、薪资
- 7. 查看岗位是teacher且名字是jin开头的员工姓名、年薪
```python
select name,age from employee where post = 'teacher';
select name,age from employee where post='teacher' and age > 30;
select name,age,salary from employee where post='teacher' and salary between 9000 and 10000;
select * from employee where post_comment is not null;
select name,age,salary from employee where post='teacher' and salary in (10000,9000,30000);
select name,age,salary from employee where post='teacher' and salary not in (10000,9000,30000);
select name,salary*12 from employee where post='teacher' and name like 'jin%';
1.5 分组查询:GROUP BY
2、分组指的是:将所有记录按照某个相同字段进行归类,比如针对员工信息表的职位分组,或者按照性别进行分组等
3、为何要分组呢?
取每个部门的最高工资
取每个部门的员工数
取男人数和女人数
小窍门:‘每’这个字后面的字段,就是我们分组的依据
4、大前提:
可以按照任意字段分组,但是分组完毕后,比如group by post,只能查看post字段,如果想查看组内信息,需要借助于聚合函数
- **ONLY_FULL_GROUP_BY**
```python
# !!!SQL_MODE设置!!!
#查看MySQL 5.7默认的sql_mode如下:
mysql> select @@global.sql_mode;
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
#!!!注意
ONLY_FULL_GROUP_BY的语义就是确定select target list中的所有列的值都是明确语义,简单的说来,在ONLY_FULL_GROUP_BY模式下,target list中的值要么是来自于聚集函数的结果,要么是来自于group by list中的表达式的值。
#设置sql_mole如下操作(我们可以去掉ONLY_FULL_GROUP_BY模式):
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> select @@global.sql_mode;
+-------------------+
| @@global.sql_mode |
+-------------------+
| |
+-------------------+
1 row in set (0.00 sec)
mysql> select * from emp group by post;
+----+------+--------+-----+------------+--------------+--------------+------------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+------+--------+-----+------------+--------------+--------------+------------+--------+-----------+
| 14 | 张野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 |
| 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 |
| 2 | jion | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 |
| 1 | xio | male | 18 | 2017-03-01 | teacher | NULL | 7300.33 | 401 | 1 |
+----+------+--------+-----+------------+-------------+--------------+------------+--------+-----------+
4 rows in set (0.00 sec)
#由于没有设置ONLY_FULL_GROUP_BY,于是也可以有结果,默认都是组内的第一条记录,但其实这是没有意义的
mysql> set global sql_mode='ONLY_FULL_GROUP_BY';
Query OK, 0 rows affected (0.00 sec)
mysql> quit #设置成功后,一定要退出,然后重新登录方可生效
Bye
mysql> use db1;
Database changed
mysql> select * from emp group by post; #报错
ERROR 1055 (42000): 'db1.emp.id' isn't in GROUP BY
mysql> select post,count(id) from emp group by post; #只能查看分组依据和使用聚合函数
+----------------------------+-----------+
| post | count(id) |
+----------------------------+-----------+
| operation | 5 |
| sale | 5 |
| teacher | 8 |
+----------------------------+-----------+
4 rows in set (0.00 sec)
- GROUP BY ```python 单独使用GROUP BY关键字分组 SELECT post FROM employee GROUP BY post; 注意:我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数
GROUP BY关键字和GROUP_CONCAT()函数一起使用 SELECT post,GROUP_CONCAT(name) FROM employee GROUP BY post;#按照岗位分组,并查看组内成员名 SELECT post,GROUP_CONCAT(name) as emp_members FROM employee GROUP BY post;
GROUP BY与聚合函数一起使用 select post,count(id) as count from employee group by post;#按照岗位分组,并查看每个组有多少人
**强调:**
```python
如果我们用unique的字段作为分组的依据,则每一条记录自成一组,这种分组没有意义
多条记录之间的某个字段值相同,该字段通常用来作为分组的依据
示例: SELECT COUNT() FROM employee; SELECT COUNT() FROM employee WHERE depart_id=1; SELECT MAX(salary) FROM employee; SELECT MIN(salary) FROM employee; SELECT AVG(salary) FROM employee; SELECT SUM(salary) FROM employee; SELECT SUM(salary) FROM employee WHERE depart_id=3;
例:<br />. 查询岗位名以及岗位包含的所有员工名字<br />. 查询岗位名以及各岗位内包含的员工个数<br />. 查询公司内男员工和女员工的个数<br />. 查询岗位名以及各岗位的平均薪资<br />. 查询岗位名以及各岗位的最高薪资<br />. 查询岗位名以及各岗位的最低薪资<br />. 查询男员工与男员工的平均薪资,女员工与女员工的平均薪资
```python
#题1:分组
mysql> select post,group_concat(name) from employee group by post;
#题目2:
mysql> select post,count(id) from employee group by post;
#题目3:
mysql> select sex,count(id) from employee group by sex;
#题目4:
mysql> select post,avg(salary) from employee group by post;
#题目5
mysql> select post,max(salary) from employee group by post;
#题目6
mysql> select post,min(salary) from employee group by post;
#题目七
mysql> select sex,avg(salary) from employee group by sex;
1.6 HAVING过滤
HAVING与WHERE不一样的地方在于!!!!!!
#!!!执行优先级从高到低:where > group by > having
#1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。
#2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,可以使用聚合函数
验证:
mysql> select @@sql_mode;
+--------------------+
| @@sql_mode |
+--------------------+
| ONLY_FULL_GROUP_BY |
+--------------------+
1 row in set (0.00 sec)
mysql> select * from emp where salary > 100000;
+----+------+------+-----+------------+---------+--------------+------------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+------+------+-----+------------+---------+--------------+------------+--------+-----------+
| 2 | jion | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 |
+----+------+------+-----+------------+---------+--------------+------------+--------+-----------+
1 row in set (0.00 sec)
mysql> select * from emp having salary > 100000;
ERROR 1463 (42000): Non-grouping field 'salary' is used in HAVING clause
mysql> select post,group_concat(name) from emp group by post having salary > 10000;#错误,分组后无法直接取到salary字段
ERROR 1054 (42S22): Unknown column 'salary' in 'having clause'
mysql> select post,group_concat(name) from emp group by post having avg(salary) > 10000;
+-----------+-------------------------------------------------------+
| post | group_concat(name) |
+-----------+-------------------------------------------------------+
| operation | 程咬铁,程咬铜,程咬银,程咬金,张野 |
| teacher | 成龙,jinxin,jingliyang,liwenzhou,yuanhao,wupeiqi,jion,xio |
+-----------+-------------------------------------------------------+
2 rows in set (0.00 sec)
例:
- 查询各岗位内包含的员工个数小于2的岗位名、岗位内包含员工名字、个数
- 查询各岗位平均薪资大于10000的岗位名、平均工资
题目2:
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000;
题目3:
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 and avg(salary) <20000;
<a name="s0rmK"></a>
### 1.7 查询排序:ORDER BY
```python
按单列排序
SELECT * FROM employee ORDER BY salary;
SELECT * FROM employee ORDER BY salary ASC;
SELECT * FROM employee ORDER BY salary DESC;
按多列排序:先按照age排序,如果年纪相同,则按照薪资排序
SELECT * from employee
ORDER BY age,
salary DESC;
例:
- 查询所有员工信息,先按照age升序排序,如果age相同则按照hire_date降序排序
- 查询各岗位平均薪资大于10000的岗位名、平均工资,结果按平均薪资升序排列
题目2
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) asc;
题目3
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) desc;
<a name="R5XNS"></a>
### 1.8 限制查询的记录数:LIMIT
```python
示例:
SELECT * FROM employee ORDER BY salary DESC
LIMIT 3; #默认初始位置为0
SELECT * FROM employee ORDER BY salary DESC
LIMIT 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5条
SELECT * FROM employee ORDER BY salary DESC
LIMIT 5,5; #从第5开始,即先查询出第6条,然后包含这一条在内往后查5条
例:
- 分页显示,每页5条 ```python mysql> select * from employee limit 0,5;
mysql> select * from employee limit 5,5;
mysql> select * from employee limit 10,5;
<a name="1KARu"></a>
### 1.9 使用正则表达式查询
```python
SELECT * FROM employee WHERE name REGEXP '^on';
SELECT * FROM employee WHERE name REGEXP 'on$';
SELECT * FROM employee WHERE name REGEXP 'm{2}';
小结:对字符串匹配的方式
WHERE name = 'xio';
WHERE name LIKE 'yua%';
WHERE name REGEXP 'on$';
例:
查看所有员工中名字是jin开头,x或者y结果的员工信息
select * from employee where name regexp '^jin.*[xy]$';
2. 多表查询
准备表 ```python
建表
create table department( id int, name varchar(20) );
create table employee( id int primary key auto_increment, name varchar(20), sex enum(‘male’,’female’) not null default ‘male’, age int, dep_id int );
插入数据
insert into department values (200,’技术’), (201,’人力资源’), (202,’销售’), (203,’运营’);
insert into employee(name,sex,age,dep_id) values (‘xio’,’male’,18,200), (‘jion’,’female’,48,201), (‘wupeiqi’,’male’,38,201), (‘yuanhao’,’female’,28,202), (‘liwenzhou’,’male’,18,200), (‘jingliyang’,’female’,18,204) ;
查看表结构和数据
mysql> desc department; +———-+——————-+———+——-+————-+———-+ | Field | Type | Null | Key | Default | Extra | +———-+——————-+———+——-+————-+———-+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +———-+——————-+———+——-+————-+———-+
mysql> desc employee; +————+———————————-+———+——-+————-+————————+ | Field | Type | Null | Key | Default | Extra | +————+———————————-+———+——-+————-+————————+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum(‘male’,’female’) | NO | | male | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | | NULL | | +————+———————————-+———+——-+————-+————————+
mysql> select * from department; +———+———————+ | id | name | +———+———————+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +———+———————+
mysql> select * from employee; +——+——————+————+———+————+ | id | name | sex | age | dep_id | +——+——————+————+———+————+ | 1 | xio | male | 18 | 200 | | 2 | jion | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +——+——————+————+———+————+
<a name="GOhFQ"></a>
### 2.1 多表连接查询
```python
#重点:外链接语法
SELECT 字段列表
FROM 表1 INNER|LEFT|RIGHT JOIN 表2
ON 表1.字段 = 表2.字段;
交叉连接:不适用任何匹配条件。生成笛卡尔积
mysql> select * from dep,emp;
+------+--------------+----+--------+--------+------+--------+
| id | name | id | name | sex | age | dep_id |
+------+--------------+----+--------+--------+------+--------+
| 200 | 技术 | 1 | xio | male | 18 | 200 |
| 201 | 人力资源 | 1 | xio | male | 18 | 200 |
| 202 | 销售 | 1 | xio | male | 18 | 200 |
| 203 | 运营 | 1 | xio | male | 18 | 200 |
| 200 | 技术 | 2 | jiaxin | female | 48 | 201 |
| 201 | 人力资源 | 2 | jiaxin | female | 48 | 201 |
| 202 | 销售 | 2 | jiaxin | female | 48 | 201 |
| 203 | 运营 | 2 | jiaxin | female | 48 | 201 |
| 200 | 技术 | 3 | haojie | male | 18 | 201 |
| 201 | 人力资源 | 3 | haojie | male | 18 | 201 |
| 202 | 销售 | 3 | haojie | male | 18 | 201 |
| 203 | 运营 | 3 | haojie | male | 18 | 201 |
| 200 | 技术 | 4 | nick | male | 28 | 202 |
| 201 | 人力资源 | 4 | nick | male | 28 | 202 |
| 202 | 销售 | 4 | nick | male | 28 | 202 |
| 203 | 运营 | 4 | nick | male | 28 | 202 |
| 200 | 技术 | 5 | owen | male | 18 | 203 |
| 201 | 人力资源 | 5 | owen | male | 18 | 203 |
| 202 | 销售 | 5 | owen | male | 18 | 203 |
| 203 | 运营 | 5 | owen | male | 18 | 203 |
| 200 | 技术 | 6 | jerry | female | 18 | 204 |
| 201 | 人力资源 | 6 | jerry | female | 18 | 204 |
| 202 | 销售 | 6 | jerry | female | 18 | 204 |
| 203 | 运营 | 6 | jerry | female | 18 | 204 |
+------+--------------+----+--------+--------+------+--------+
24 rows in set (0.00 sec)
内连接:只连接匹配的行 ```python
找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果
department没有204这个部门,因而employee表中关于204这条员工信息没有匹配出来
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id; +——+—————-+———+————+———————+ | id | name | age | sex | name | +——+—————-+———+————+———————+ | 1 | xio | 18 | male | 技术 | | 2 | jion | 48 | female | 人力资源 | | 3 | wupeiqi | 38 | male | 人力资源 | | 4 | yuanhao | 28 | female | 销售 | | 5 | liwenzhou | 18 | male | 技术 | +——+—————-+———+————+———————+
上述sql等同于
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;
- **外链接之左连接:优先显示左表全部记录**
```python
#以左表为准,即找出所有员工信息,当然包括没有部门的员工
#本质就是:在内连接的基础上增加左边有右边没有的结果
mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id;
+----+------------+--------------+
| id | name | depart_name |
+----+------------+--------------+
| 1 | xio | 技术 |
| 5 | liwenzhou | 技术 |
| 2 | jion | 人力资源 |
| 3 | wupeiqi | 人力资源 |
| 4 | yuanhao | 销售 |
| 6 | jingliyang | NULL |
+----+------------+--------------+
外链接之右连接:优先显示右表全部记录
#以右表为准,即找出所有部门信息,包括没有员工的部门
#本质就是:在内连接的基础上增加右边有左边没有的结果
mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id;
+------+-----------+--------------+
| id | name | depart_name |
+------+-----------+--------------+
| 1 | xio | 技术 |
| 2 | jion | 人力资源 |
| 3 | wupeiqi | 人力资源 |
| 4 | yuanhao | 销售 |
| 5 | liwenzhou | 技术 |
| NULL | NULL | 运营 |
+------+-----------+--------------+
全外连接:显示左右两个表全部记录 ```python 全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果
注意:mysql不支持全外连接 full JOIN
强调:mysql可以使用此种方式间接实现全外连接
select from employee left join department on employee.dep_id = department.id union select from employee right join department on employee.dep_id = department.id ;
查看结果
+———+——————+————+———+————+———+———————+ | id | name | sex | age | dep_id | id | name | +———+——————+————+———+————+———+———————+ | 1 | xio | male | 18 | 200 | 200 | 技术 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | | 2 | jion | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 6 | jingliyang | female | 18 | 204 | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | 203 | 运营 | +———+——————+————+———+————+———+———————+
注意 union与union all的区别:union会去掉相同的纪录
**
<a name="mUJMX"></a>
### 2.2 符合条件连接查询
```python
#示例1:以内连接的方式查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门
select employee.name,department.name from employee inner join department
on employee.dep_id = department.id
where age > 25;
#示例2:以内连接的方式查询employee和department表,并且以age字段的升序方式显示
select employee.id,employee.name,employee.age,department.name from employee,department
where employee.dep_id = department.id
and age > 25
order by age asc;
2.3 子查询
#1:子查询是将一个查询语句嵌套在另一个查询语句中。
#2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
#3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
#4:还可以包含比较运算符:= 、 !=、> 、<等
- 带IN关键字的子查询
```python
查询平均年龄在25岁以上的部门名
select id,name from department where id in(select dep_id from employee group by dep_id having avg(age) > 25);
查看技术部员工姓名
select name from employee where dep_id in (select id from department where name=’技术’);
查看不足1人的部门名(子查询得到的是有人的部门id)
select name from department where id not in (select distinct dep_id from employee);
```python
# !!!注意not in
not in 无法处理null的值,即子查询中如果存在null的值,not in将无法处理,如下
mysql> select * from emp;
+----+------------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+------------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | female | 18 | 204 |
| 7 | xxx | male | 19 | NULL |
+----+------------+--------+------+--------+
7 rows in set (0.00 sec)
mysql> select * from dep;
+------+--------------+
| id | name |
+------+--------------+
| 200 | 技术 |
| 201 | 人力资源 |
| 202 | 销售 |
| 203 | 运营 |
+------+--------------+
4 rows in set (0.00 sec)
# 子查询中存在null
mysql> select * from dep where id not in (select distinct dep_id from emp);
Empty set (0.00 sec)
# 解决方案如下
mysql> select * from dep where id not in (select distinct dep_id from emp where dep_id is not null);
+------+--------+
| id | name |
+------+--------+
| 203 | 运营 |
+------+--------+
1 row in set (0.00 sec)
mysql>
ANY 和 IN 运算符不同之处1
ANY 必须和其他的比较运算符共同使用,而且ANY必须将比较运算符放在 ANY 关键字之前,所比较的值需要匹配子查询中的任意一个值,这也就是 ANY 在英文中所表示的意义
例如:使用 IN 和使用 ANY运算符得到的结果是一致的 select * from employee where salary = any ( select max(salary) from employee group by depart_id);
select * from employee where salary in ( select max(salary) from employee group by depart_id);
结论:也就是说“=ANY”等价于 IN 运算符,而“<>ANY”则等价于 NOT IN 运算符
ANY和 IN 运算符不同之处2
ANY 运算符不能与固定的集合相匹配,比如下面的 SQL 语句是错误的
SELECT * FROM T_Book WHERE FYearPublished < ANY (2001, 2003, 2005)
- **带ALL关键字的子查询**
```python
# all同any类似,只不过all表示的是所有,any表示任一
查询出那些薪资比所有部门的平均薪资都高的员工=》薪资在所有部门平均线以上的狗币资本家
select * from employee where salary > all (
select avg(salary) from employee group by depart_id);
查询出那些薪资比所有部门的平均薪资都低的员工=》薪资在所有部门平均线以下的无产阶级劳苦大众
select * from employee where salary < all (
select avg(salary) from employee group by depart_id);
查询出那些薪资比任意一个部门的平均薪资低的员工=》薪资在任一部门平均线以下的员工select * from employee where salary < any ( select avg(salary) from employee group by depart_id);
查询出那些薪资比任意一个部门的平均薪资高的员工=》薪资在任一部门平均线以上的员工
select * from employee where salary > any (
select avg(salary) from employee group by depart_id);
- 带比较运算符的子查询
```python
比较运算符:=、!=、>、>=、<、<=、<>
查询大于所有人平均年龄的员工名与年龄
mysql> select name,age from emp where age > (select avg(age) from emp); +————-+———+ | name | age | +————-+———+ | xio | 48 | | wupeiqi | 38 | +————-+———+ 2 rows in set (0.00 sec)
查询大于部门内平均年龄的员工名、年龄
select t1.name,t1.age from emp t1 inner join (select dep_id,avg(age) avg_age from emp group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age;
- **带EXISTS关键字的子查询**
EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。<br />而是返回一个真假值。True或False<br />当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询
```python
#department表中存在dept_id=203,Ture
mysql> select * from employee
-> where exists
-> (select id from department where id=200);
+----+------------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+------------+--------+------+--------+
| 1 | xio | male | 18 | 200 |
| 2 | jion | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | female | 18 | 204 |
+----+------------+--------+------+--------+
#department表中存在dept_id=205,False
mysql> select * from employee
-> where exists
-> (select id from department where id=204);
Empty set (0.00 sec)
in与exists
!!!!!!当in和exists在查询效率上比较时,in查询的效率快于exists的查询效率!!!!!!
==============================exists==============================
# exists
exists后面一般都是子查询,后面的子查询被称做相关子查询(即与主语句相关),当子查询返回行数时,exists条件返回true,
否则返回false,exists是不返回列表的值的,exists只在乎括号里的数据能不能查找出来,是否存在这样的记录。
# 例
查询出那些班级里有学生的班级
select * from class where exists (select * from stu where stu.cid=class.id)
# exists的执行原理为:
1、依次执行外部查询:即select * from class
2、然后为外部查询返回的每一行分别执行一次子查询:即(select * from stu where stu.cid=class.cid)
3、子查询如果返回行,则exists条件成立,条件成立则输出外部查询取出的那条记录
==============================in==============================
# in
in后跟的都是子查询,in()后面的子查询 是返回结果集的
# 例
查询和所有女生年龄相同的男生
select * from stu where sex='男' and age in(select age from stu where sex='女')
# in的执行原理为:
in()的执行次序和exists()不一样,in()的子查询会先产生结果集,
然后主查询再去结果集里去找符合要求的字段列表去.符合要求的输出,反之则不输出.
- not in与 not exists ```python !!!!!!not exists查询的效率远远高与not in查询的效率。!!!!!!
==============================not in============================== not in()子查询的执行顺序是: 为了证明not in成立,即找不到,需要一条一条地查询表,符合要求才返回子查询的结果集,不符合的就继续查询下一条记录,直到把表中的记录查询完,只能查询全部记录才能证明,并没有用到索引。
==============================not exists============================== not exists: 如果主查询表中记录少,子查询表中记录多,并有索引。 例如:查询那些班级中没有学生的班级 select * from class
where not exists
(select * from student where student.cid = class.cid)
not exists的执行顺序是: 在表中查询,是根据索引查询的,如果存在就返回true,如果不存在就返回false,不会每条记录都去查询。
---
<a name="nNNhy"></a>
# 六 权限管理
![](https://cdn.nlark.com/yuque/0/2021/png/12472135/1614824979460-b3ffad48-53f2-4aa1-a08b-f1cffaeb0e2a.png#align=left&display=inline&height=827&margin=%5Bobject%20Object%5D&name=&originHeight=827&originWidth=666&size=0&status=done&style=none&width=666)
```python
#授权表
user #该表放行的权限,针对:所有数据,所有库下所有表,以及表下的所有字段
db #该表放行的权限,针对:某一数据库,该数据库下的所有表,以及表下的所有字段
tables_priv #该表放行的权限。针对:某一张表,以及该表下的所有字段
columns_priv #该表放行的权限,针对:某一个字段
#按图解释:
user:放行db1,db2及其包含的所有
db:放行db1,及其db1包含的所有
tables_priv:放行db1.table1,及其该表包含的所有
columns_prive:放行db1.table1.column1,只放行该字段
权限相关操作
#创建用户
create user 'aaaa'@'1.1.1.1' identified by '123';
create user 'aaaa'@'192.168.1.%' identified by '123';
create user 'aaaa'@'%' identified by '123';
#授权:对文件夹,对文件,对文件某一字段的权限
查看帮助:help grant
常用权限有:select,update,alter,delete
all可以代表除了grant之外的所有权限
#针对所有库的授权:*.*
grant select on *.* to 'aaaa'@'localhost' identified by '123'; #只在user表中可以查到aaaa1用户的select权限被设置为Y
#针对某一数据库:db1.*
grant select on db1.* to 'aaaa2'@'%' identified by '123'; #只在db表中可以查到aaaa2用户的select权限被设置为Y
#针对某一个表:db1.t1
grant select on db1.t1 to 'aaaa3'@'%' identified by '123'; #只在tables_priv表中可以查到aaaa3用户的select权限
#针对某一个字段:
mysql> select * from t3;
+------+-------+------+
| id | name | age |
+------+-------+------+
| 1 | aaaa1 | 18 |
| 2 | aaaa2 | 19 |
| 3 | aaaa3 | 29 |
+------+-------+------+
grant select (id,name),update (age) on db1.t3 to 'aaaa4'@'localhost' identified by '123';
#可以在tables_priv和columns_priv中看到相应的权限
mysql> select * from tables_priv where user='aaaa4'\G
*************************** 1. row ***************************
Host: localhost
Db: db1
User: aaaa4
Table_name: t3
Grantor: root@localhost
Timestamp: 0000-00-00 00:00:00
Table_priv:
Column_priv: Select,Update
row in set (0.00 sec)
mysql> select * from columns_priv where user='egon4'\G
*************************** 1. row ***************************
Host: localhost
Db: db1
User: aaaa4
Table_name: t3
Column_name: id
Timestamp: 0000-00-00 00:00:00
Column_priv: Select
*************************** 2. row ***************************
Host: localhost
Db: db1
User: aaaa4
Table_name: t3
Column_name: name
Timestamp: 0000-00-00 00:00:00
Column_priv: Select
*************************** 3. row ***************************
Host: localhost
Db: db1
User: aaaa4
Table_name: t3
Column_name: age
Timestamp: 0000-00-00 00:00:00
Column_priv: Update
rows in set (0.00 sec)
#删除权限
revoke select on db1.* from 'aaaa'@'%';