一、简单了解一下 mysql 的 sql 类型:
1、数据定义语言 DDL:Create、Drop、Alter 操作。用于定义库和表结构的。
2、数据操纵语言 DML:insert、update、delete。对行记录进行增删改操作。
3、数据查询语言 DQL:select。用于查询数据的。
4、数据控制语言 DCL:grant、revoke、commit、rollback。控制数据库的权限和事务。
二、DQL:SELECT子语句查询
2.1、SELECT查询加强
-- 使用 where 子句
-- 如何查找 1992.1.1 后入职的员工?
SELECT * FROM emp
WHERE hiredate > '1992-01-01'
-- 如何使用 like 操作符(模糊)
-- %: 表示 0 到多个任意字符 _: 表示单个任意字符
-- 如何显示首字符为 S 的员工姓名和工资?
SELECT ename, sal FROM emp
WHERE ename LIKE 'S%
-- 如何显示第三个字符为大写 O 的所有员工的姓名和工资?
SELECT ename, sal FROM emp
WHERE ename LIKE '__O%
-- ■ 如何显示没有上级的雇员的情况
SELECT * FROM emp
WHERE mgr IS NULL;
-- ■ 查询表结构
DESC emp
-- 使用 order by 子句
-- 如何按照工资的从低到高的顺序[升序],显示雇员的信息?
SELECT * FROM emp
ORDER BY sal
-- 按照部门号升序而雇员的工资降序排列 , 显示雇员信息?
SELECT * FROM emp
ORDER BY deptno ASC , sal DESC;
2.2、分页查询
SELECT ...
LIMIT start ,rows
表示从start+1开始,取出rows行,start是从0开始的
-- 分页查询
-- 按雇员的 id 号升序取出, 每页显示 3 条记录,请分别显示 第 1 页,第 2 页,第 3 页
-- 第 1 页
SELECT * FROM emp
ORDER BY empno
LIMIT 0, 3;
-- 第 2 页
SELECT * FROM emp
ORDER BY empno
LIMIT 3, 3;
-- 第 3 页
SELECT * FROM emp
ORDER BY empno
LIMIT 6, 3;
-- 推导一个公式
SELECT * FROM emp
ORDER BY empno
LIMIT 每页显示记录数 * ( 第几页 -1) , 每页显示记录数
-- 应用案例:请统计各个部门 group by 的平均工资 avg,
-- 并且是大于 1000 的 having,并且按照平均工资从高到低排序, order by
-- 取出前两行记录 limit 0,2
SELECT AVG(sal) AS avg_sal FROM emp
GROUP BY deptno
HAVING avg_sal > 1000
ORDER BY avg_sal DSCE
LIMIT 0,2
数据分组的总结:
如果SELECT语句同时含有group by,having,limit,order by。那么他们的顺序是:
group by
having
order by
limit
三、多表查询
3.1、多表查询--笛卡尔集
多表查询是指基于两张或两张以上的表查询,在实际应用中,查询单个表可能不能满足你的需求,应找到多张表所能关联起来的字段以及他们的关系。作为WHERE子语句的条件进行筛选。
笛卡尔集:假设集合A={a, b, c, d},集合B={0, 1, 2},则两个集合的笛卡尔积为:
{(a, 0), (a, 1), (a, 2),
(b, 0), (b, 1), (b, 2),
(c, 0), (c, 1), (c, 2),
(d, 0), (d, 1), (d, 2)
}SELECT * FROM emp(13行),dept(4行)
会显示这两张表所有信息的组合,一共13*4=52行数据。emp表中的每一行数据都会跟dept中的四行数据进行组合,这种方式叫笛卡尔集。因此必须加筛选条件,找到两张表列中的有关联的,并在WHERE子句中限制。
如emp员工表中部门编号deptno和dept部门表中的deptno应该相等
WHERE emp.deptno = dept.deptno
多表查询的条件不能少于 表的个数-1, 否则会出现笛卡尔集
--显示雇员名,雇员工资及所在部门的名字 【笛卡尔集】
--1. 雇员名,雇员工资 来自 emp 表
--2. 部门的名字 来自 dept 表
--3. 需求对 emp 和 dept 查询 ename,sal,dname,deptno
--4. 当我们需要指定显示某个表的列是,需要 表.列表
#多表查询的条件不能少于 表的个数-1, 否则会出现笛卡尔集
SELECT ename,sal,dname,emp.deptno
FROM emp, dept
WHERE emp.deptno = dept.deptno
-- 如何显示部门号为 10 的部门名、员工名和工资?
SELECT dname as 部门名称,dept.deptno as 部门编号,ename as 员工姓名,sal as 工资
FROM emp,dept
WHERE dept.deptno = emp.deptno AND emp.deptno = 10;
-- 显示各个员工的姓名,工资,及其工资的级别?
-- 思路 姓名,工资 来自 emp 13
-- 工资级别 salgrade 5
-- 写sql , 先写一个简单,然后加入过滤条件...
select ename, sal, grade
from emp , salgrade
where sal between losal and hisal;
3.2、自连接----一张表组合成多张表的自连接查询
自连接是指在同一张表的连接查询(将同一张表看作两张表)
-- 思考题: 显示公司员工名字和他的上级的名字?
-- 员工名字 在 emp, 上级的名字的名字 emp,且上级名字并不是单独一个字段(列)
-- 员工和上级是通过 emp 表的 mgr 列关联
-- 自连接的特点:
-- 1. 把同一张表当做两张表使用
-- 2. 需要给表取别名 表名 表别名
-- 3. 列名不明确,可以指定列的别名 列名 as 列的别名
SELECT worker.ename AS '职员名' , boss.ename AS '上级名'
FROM emp worker, emp boss
WHERE worker.mgr = boss.empno;
四、表的子查询---嵌套子查询
子查询是指嵌入在其它 sql 语句中的 select 语句 , 也叫嵌套查询
单行子查询:是指只返回一行数据的子查询语句
多行子查询:是指返回多行数据的子查询 返回多个结果,使用关键字 in筛选
4.1、使用嵌套子查询-- 多行子查询注意使用in
-- 请思考:如何显示与 SMITH 同一部门的所有员工?
/*
1. 先查询到 SMITH 的部门号得到
2. 把上面的 select 语句当做一个子查询来使用
*/
SELECT deptno
FROM emp
WHERE ename = 'SMITH'
-- 下面的答案.
SELECT * FROM emp
WHERE deptno = ( SELECT deptno
FROM emp
WHERE ename = 'SMITH' )
-- 课堂练习:如何查询和部门 10 的工作相同的雇员的名字、岗位、工资、部门号, 但是不含10号部门自己=--- 的雇员.
--1、部门10下的工作,返回多行,,要去重
SELECT DISTINCT job FROM emp
WHERE deptno =10
--2、将这个查询结果作为一个查询约束条件,多行子查询
SELECT ename,job,sal,deptno FROM emp
WHERE job in (SELECT DISTINCT job FROM emp WHERE deptno =10)
AND deptno!=10
4.2、子查询当做临时表使用---构成多表查询
-- 查询 ecshop 中各个类别中,价格最高的商品的信息
-- 查询 商品表
-- 先得到 各个类别中,价格最高的商品 max + group by cat_id, 当做临时表
-- 把子查询当做一张临时表可以解决很多很多复杂的查询
SELECT cat_id , max(shop_price)
FROM ecs_goods
GROUP BY cat_id
SELECT goods_id, ecs_goods.cat_id, goods_name, shop_price
FROM (
SELECT cat_id , MAX(shop_price) as max_price
FROM ecs_goods
GROUP BY cat_id
) temp , ecs_goods
where temp.cat_id = ecs_goods.cat_id
AND temp.max_price = ecs_goods.shop_price
4.3、all 和 any 的使用
-- 请思考:显示工资比部门 30 的所有员工的工资高的员工的姓名、工资和部门号
--显示工资比部门 30 的所有员工的工资高的员工的姓名、工资和部门号
SELECT ename, sal, deptno
FROM emp
WHERE sal > ALL(
SELECT sal
FROM emp
WHERE deptno = 30
)
--另一种方法:
SELECT ename, sal, deptno
FROM emp
WHERE sal > (
SELECT MAX(sal)
FROM emp
WHERE deptno = 30
)
-- 请思考:如何显示工资比部门 30 的其中一个员工的工资高的员工的姓名、工资和部门号
--如何显示工资比部门 30 的其中一个员工的工资高的员工的姓名、工资和部门号
SELECT ename, sal, deptno
FROM emp
WHERE sal >ANY(
SELECT sal
FROM emp
WHERE deptno = 30
)
--另一种方法:
SELECT ename, sal, deptno
FROM emp
WHERE sal > (
SELECT MIN(sal)
FROM emp
WHERE deptno = 30
)
4.4、多列子查询
多列子查询是指返回多个列数据的子查询语句
--请查询 和宋江数学,英语,语文成绩 完全相同的学生
#返回的是宋江的数学英语语文成绩,三列数据
SELECT math,english,chinese FROM student
WHERE name = "宋江";
SELECT * FROM student
WHERE (math,english,chinese) = (SELECT math,english,chinese FROM student
WHERE name = "宋江";
)
--请思考如何查询与 allen 的部门和岗位完全相同的所有雇员(并且不含 allen 本人)
-- (字段 1, 字段 2 ...) = (select 字段 1,字段 2 from 。。。。)
-- 分析: 1. 得到 smith 的部门和岗位
SELECT deptno , job
FROM emp
WHERE ename = 'ALLEN'
-- 分析: 2 把上面的查询当做子查询来使用,并且使用多列子查询的语法进行匹配
SELECT *
FROM emp
WHERE (deptno , job) = (
SELECT deptno , job
FROM emp
WHERE ename = 'ALLEN'
)
AND ename != 'ALLEN'
4.5、在 from 子句中使用子查询
-- 请思考:查找每个部门工资高于本部门平均工资的人的资料
-- 这里要用到数据查询的小技巧,把一个子查询当作一个临时表使用
-- 请思考:查找每个部门工资高于本部门平均工资的人的资料
-- 这里要用到数据查询的小技巧,把一个子查询当作一个临时表使用
-- 1. 先得到每个部门的 部门号和 对应的平均工资
SELECT deptno, AVG(sal) AS avg_sal
FROM emp GROUP BY deptno
-- 2. 把上面的结果当做子查询, 和 emp 进行多表查询
SELECT ename, sal, temp.avg_sal, emp.deptno
FROM emp, (
SELECT deptno, AVG(sal) AS avg_sal
FROM emp GROUP BY deptno
)temp
WHERE emp.deptno = temp.deptno AND emp.sal > temp.avg_sal
-- 查找每个部门工资最高的人的详细资料
SELECT ename, sal, temp.max_sal, emp.deptno
FROM emp, (
SELECT deptno, MAX(sal) AS max_sal
FROM emp
GROUP BY deptno
) temp
WHERE emp.deptno = temp.deptno AND emp.sal = temp.max_sal
表复制
4.6.1、自我复制数据(蠕虫复制)
思考:如何删除一张表的重复记录?
思路
(1) 先创建一张临时表 my_tmp , 该表的结构和 my_tab02 一样
create table my_tmp like my_tab02
(2) 把 my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmp
(3) 清除掉 my_tab02 记录
(4) 把 my_tmp 表的记录复制到 my_tab02
(5) drop 掉 临时表 my_tmp
-- 1. 先把 emp 表的记录复制到 my_tab01
INSERT INTO my_tab01 (id, `name`, sal, job,deptno)
SELECT empno, ename, sal, job, deptno FROM emp;
-- 2. 自我复制
INSERT INTO my_tab01
SELECT * FROM my_tab01;
-- 如何删除掉一张表重复记录
-- 1. 先创建一张表 my_tab02,
-- 2. 让 my_tab02 有重复的记录
-- 这个语句 把 emp 表的结构(列),复制到 my_tab02
CREATE TABLE my_tab02 LIKE emp;
INSERT INTO my_tab02
SELECT * FROM emp;
-- 3. 考虑去重 my_tab02 的记录
/*
思路
(1) 先创建一张临时表 my_tmp , 该表的结构和 my_tab02 一样
(2) 把 my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmp
(3) 清除掉 my_tab02 记录
(4) 把 my_tmp 表的记录复制到 my_tab02
(5) drop 掉 临时表 my_tmp
*/
-- (1) 先创建一张临时表 my_tmp , 该表的结构和 my_tab02 一样
create table my_tmp like my_tab02
-- (2) 把 my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmp
insert into my_tmp
select distinct * from my_tab02;
-- (3) 清除掉 my_tab02 记录
delete from my_tab02;
-- (4) 把 my_tmp 表的记录复制到 my_tab02
insert into my_tab02
select * from my_tmp;
-- (5) drop 掉 临时表 my_tmp
drop table my_tmp;
合并查询--union、union all
在实际应用中,为了合并多个SELECT语句的结果,可以使用union、union all语句
1、union all:该操作符用于取得两个结果集的并集,不会去校重复行
SELECT ename,sal,job FROM emp WHERE sal > 2500 UNION ALL
SELECT ename,sal,job FROM emp WHERE job = 'MANAGER';
2、union :该操作符与union all相似,但是会自动去掉结果中的重复行
SELECT ename,sal,job FROM emp WHERE sal > 2500 UNION
SELECT ename,sal,job FROM emp WHERE job = 'MANAGER';