MySQL
多表查询
查询语法:select 列名列表 from 表名列表 where...
准备sql
-- 创建班级表 CREATE TABLE class( id INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(20) ); INSERT INTO class(`name`) VALUES (‘信息安全‘),(‘移动通信‘),(‘计算机科学‘); SELECT * FROM class; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), gender CHAR(1), -- 性别 score DOUBLE, -- 分数 join_date DATE, -- 上学日期 class_id INT, FOREIGN KEY (class_id) REFERENCES class(id) -- 外键,关联课程表(课程表的主键) ); INSERT INTO student(NAME,gender,score,join_date,class_id) VALUES(‘孙悟空‘,‘男‘,73,‘2013-02-24‘,1); INSERT INTO student(NAME,gender,score,join_date,class_id) VALUES(‘猪八戒‘,‘男‘,90,‘2010-12-02‘,2); INSERT INTO student(NAME,gender,score,join_date,class_id) VALUES(‘唐僧‘,‘男‘,89,‘2008-08-08‘,2); INSERT INTO student(NAME,gender,score,join_date,class_id) VALUES(‘白骨精‘,‘女‘,68,‘2015-10-07‘,3); INSERT INTO student(NAME,gender,score,join_date,class_id) VALUES(‘蜘蛛精‘,‘女‘,63,‘2011-03-14‘,1); SELECT * FROM student;
笛卡尔积:
有两个集合A,B .取这两个集合的所有组成情况。
要完成多表查询,需要消除无用的数据
多表查询分类:
1. 内连接查询:
1、隐式内连接:使用where消除无用的数据
-- 查询所有学生信息和对应的班级信息 SELECT * FROM student,class WHERE class.`id`=student.`class_id`; -- 查询学生表的名称,性别。班级表的名称 SELECT student.`NAME`, student.`gender`, class.`name` FROM student,class WHERE student.`class_id`=class.`id`;
2. 显式内连接:
语法:select 字段列表 from 表1 left [outer] join 表2 on 条件;
SELECT * FROM student INNER JOIN class ON student.`class_id` = class.`id`; SELECT * FROM student JOIN class ON student.`class_id` = class.`id`; -- INNER可以省略
2、外连接查询
1、左外连接
语法:select 字段列表 from 表1 left【outer】join 表2 on 条件
查询的是左表所有数据以及其交集部分。
-- 查询所有学生信息,如果学生有班级,则查询班级名称,没有班级,则不显示班级名称 SELECT s1.*, c2.`name` FROM student s1 LEFT JOIN class c2 ON s1.`class_id` = c2.`id`
2、右外连接
语法:select 字段列表 from 表1 right【outer】 join 表2 on 条件
查询的是右表所有数据以及其交集部分。
SELECT * FROM class t2 RIGHT OUTER JOIN student t1 ON t1.`class_id` = t2.`id`;
3、子查询
查询中嵌套查询
-- 查询分数最高的学生信息 -- 查询分数最高的学生信息 SELECT MAX(score) FROM student; -- 查询学生信息,并且分数等于90的 SELECT * FROM student WHERE student.`score`=90; -- 合并为一条SQL SELECT * FROM student WHERE student.`score`=(SELECT MAX(score) FROM student);
-- 查询学生平均分小于平均分的学生 select * from student where student.score < (select avg(score) from student); -- 子查询可以作为条件,使用运算符in来判断 SELECT id FROM class WHERE NAME = ‘信息安全‘ OR NAME = ‘移动通信 ‘; SELECT * FROM student WHERE class_id = 2 OR class_id = 1; SELECT * FROM student WHERE class_id IN (SELECT id FROM class WHERE NAME = ‘信息安全‘ OR NAME = ‘移动通信 ‘ );
-- 查询学生上学日期是2011-11-11日之后的学生信息和班级信息 SELECT * FROM class c1,(SELECT * FROM student WHERE student.`join_date`>‘2011-11-11‘) s2 WHERE c1.`id`=s2.class_id; -- 普通内连接 SELECT * FROM student s1,class c2 WHERE s1.`class_id`= c2.`id` AND s1.`join_date` > ‘2011-11-11‘
4、多表练习
-- 部门表 CREATE TABLE dept ( id INT PRIMARY KEY PRIMARY KEY, -- 部门id dname VARCHAR(50), -- 部门名称 loc VARCHAR(50) -- 部门所在地 ); -- 添加4个部门 INSERT INTO dept(id,dname,loc) VALUES (10,‘教研部‘,‘北京‘), (20,‘学工部‘,‘上海‘), (30,‘销售部‘,‘广州‘), (40,‘财务部‘,‘深圳‘); -- 职务表,职务名称,职务描述 CREATE TABLE job ( id INT PRIMARY KEY, jname VARCHAR(20), description VARCHAR(50) ); -- 添加4个职务 INSERT INTO job (id, jname, description) VALUES (1, ‘董事长‘, ‘管理整个公司,接单‘), (2, ‘经理‘, ‘管理部门员工‘), (3, ‘销售员‘, ‘向客人推销产品‘), (4, ‘文员‘, ‘使用办公软件‘); -- 员工表 CREATE TABLE emp ( id INT PRIMARY KEY, -- 员工id ename VARCHAR(50), -- 员工姓名 job_id INT, -- 职务id mgr INT , -- 上级领导 joindate DATE, -- 入职日期 salary DECIMAL(7,2), -- 工资 bonus DECIMAL(7,2), -- 奖金 dept_id INT, -- 所在部门编号 CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id), CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id) ); -- 添加员工 INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES (1001,‘孙悟空‘,4,1004,‘2000-12-17‘,‘8000.00‘,NULL,20), (1002,‘卢俊义‘,3,1006,‘2001-02-20‘,‘16000.00‘,‘3000.00‘,30), (1003,‘林冲‘,3,1006,‘2001-02-22‘,‘12500.00‘,‘5000.00‘,30), (1004,‘唐僧‘,2,1009,‘2001-04-02‘,‘29750.00‘,NULL,20), (1005,‘李逵‘,4,1006,‘2001-09-28‘,‘12500.00‘,‘14000.00‘,30), (1006,‘宋江‘,2,1009,‘2001-05-01‘,‘28500.00‘,NULL,30), (1007,‘刘备‘,2,1009,‘2001-09-01‘,‘24500.00‘,NULL,10), (1008,‘猪八戒‘,4,1004,‘2007-04-19‘,‘30000.00‘,NULL,20), (1009,‘罗贯中‘,1,NULL,‘2001-11-17‘,‘50000.00‘,NULL,10), (1010,‘吴用‘,3,1006,‘2001-09-08‘,‘15000.00‘,‘0.00‘,30), (1011,‘沙僧‘,4,1004,‘2007-05-23‘,‘11000.00‘,NULL,20), (1012,‘李逵‘,4,1006,‘2001-12-03‘,‘9500.00‘,NULL,30), (1013,‘小白龙‘,4,1004,‘2001-12-03‘,‘30000.00‘,NULL,20), (1014,‘关羽‘,4,1007,‘2002-01-23‘,‘13000.00‘,NULL,10); -- 工资等级表 CREATE TABLE salarygrade ( grade INT PRIMARY KEY, -- 级别 losalary INT, -- 最低工资 hisalary INT -- 最高工资 ); -- 添加5个工资等级 INSERT INTO salarygrade(grade,losalary,hisalary) VALUES (1,7000,12000), (2,12010,14000), (3,14010,20000), (4,20010,30000), (5,30010,99990);
-- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述 SELECT e1.`id`, -- 员工编号 e1.`ename`, -- 员工姓名 e1.`salary`,-- 工资 j1.`jname`, -- 职务名称 j1.`description` -- 职务描述 FROM emp e1, job j1 WHERE e1.`job_id` = j1.`id`; -- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置 SELECT e1.`id`, e1.`ename`, e1.`salary`, j1.`jname`, j1.`description`, d1.`dname`, d1.`loc` FROM emp e1,job j1,dept d1 WHERE e1.`dept_id`=d1.`id` AND e1.`job_id`=j1.`id` -- 3.查询员工姓名,工资,工资等级 SELECT e1.`ename`, e1.`salary`, s1.* FROM emp e1,salarygrade s1 WHERE e1.`salary` BETWEEN s1.`losalary` AND s1.`hisalary`; -- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级 -- emp job dept salarygrade -- emp.job_id = job.id and emp.dept_id =dept.id and -- emp.salary BETWEEN salarygrade.losalary and salarygrade.hisalary SELECT e1.`ename`, e1.`salary`, j1.`jname`, j1.`description`, d1.`dname`, d1.`loc`, s1.`grade` FROM emp e1,job j1,dept d1,salarygrade s1 WHERE e1.`job_id` = j1.`id` AND e1.`dept_id` =d1.`id` AND e1.`salary` BETWEEN s1.`losalary` AND s1.`hisalary` -- 5.查询出部门编号、部门名称、部门位置、部门人数 -- dept emp SELECT dept_id,COUNT(id) total FROM emp GROUP BY dept_id; SELECT d1.`id`,d1.`dname`,d1.`loc` , e1.total FROM dept d1, (SELECT dept_id,COUNT(id) total FROM emp GROUP BY dept_id ) e1 WHERE d1.`id` = e1.dept_id -- 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询 SELECT e1.`ename`, e1.`mgr`, e2.`id`, e2.`ename` FROM emp e1 LEFT JOIN emp e2 ON e1.`mgr` =e2.`id`;
5、事务
1、概念:如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败
2、操作:
1.开启事务:start transaction;
2.回滚:rollback;(执行出现问题)
3.提交:commit;(执行没有问题)
3、事务提交的两种方式:
自动提交:MySQL
手动提交:Oracle
4、 修改事务的默认提交方式:
SELECT @@autocommit;(1代表自动提交,0代表手动提交)
set @@autocommit = 0;
事务的四大特性:
1、原子性:表示不可分割的最小操作单位,要么同时成功,要么同时失败
2、持久性:当事务提交或回滚后,数据库将持久化保存数据
3、隔离性:多个事务之间是相互独立的
4、一致性:事务操作前后,数据总量保持不变
事务隔离级别:
虽然多个事务之间是隔离且相互独立的,但当多个事务同时操作同一数据时,会引发一些问题,此时我们就需要设置不同的隔离级别来解决
存在的问题:
1、脏读:一个事务读取到另一个事务没有提交的数据
2、不可重复读:在同一事务中,两次读取到的数据不一致
3、幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
隔离级别:
读未提交:read uncommitted(脏读,不可重复读,幻读)1
读已提交:read committed(不可重复读,幻读)(Orcal) 2
可重复读:repeatable read(幻读)(MySQL) 3
串行化:serializable(安全性最高,效率最低) 4(隔离级别)
set global transaction isolation level 隔离级别(read uncommitted)---设置隔离级别
DCL:数据控制语言
DCL:管理用户,授权
1、用户管理
USE mysql; SELECT * FROM USER; -- 查看用户 CREATE USER ‘demo‘@‘localhost‘ IDENTIFIED BY ‘123‘; -- 添加用户 UPDATE USER SET PASSWORD = PASSWORD(‘1234‘)WHERE USER = ‘demo‘; SET PASSWORD FOR ‘demo‘@‘localhost‘ =PASSWORD(‘abc‘); -- 修改用户密码 -- mysql中忘记了root用户的密码?使用无验证方式启动mysql服务: mysqld --skip-grant-tables
2、权限管理
SHOW GRANTS FOR ‘root‘@‘localhost‘; -- 查询权限 SHOW GRANTS FOR ‘lisi‘@‘%‘;-- % 表示可以在任意主机使用用户登录数据库 -- grant 权限列表 on 数据库名.表名 to ‘用户名‘@‘主机名‘; GRANT ALL ON *.* TO ‘zhangsan‘@‘localhost‘; -- 授予权限,任意数据库任意表 REVOKE UPDATE ON db3.`account` FROM ‘lisi‘@‘%‘;-- 撤销权限 revoke 权限列表 on 数据库名.表名 from ‘用户名‘@‘主机名‘;