MySQL学习笔记①_案例记录


若文章内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系博主删除。


在这里插入图片描述



本博客是 《MySQL 学习笔记①》的案例补充。


写这篇博客旨在制作笔记,方便个人在线阅览,巩固知识。

博客的内容主要来自视频内容和资料中提供的学习笔记。



1.DDL


1.1.数据库操作


  • 创建数据库
CREATE DATABASE IF NOT EXISTS itcast DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;

  • 使用数据库
USE itcast;

1.2.表操作


  • 案例:创建一张员工信息表
    • 设计要求如下:
      • 编号(纯数字)
      • 员工工号 (字符串类型,长度不超过 10 位)
      • 员工姓名(字符串类型,长度不超过 10 位)
      • 性别(男/女,存储一个汉字)
      • 年龄(正常人年龄,不可能存储负数)
      • 身份证号(二代身份证号均为 18 位,身份证中有 X 这样的字符)
      • 入职时间(取值年月日即可)
CREATE TABLE emp(
	id INT COMMENT '编号',
	workno VARCHAR(10) COMMENT '工号',
	name VARCHAR(10) COMMENT '姓名',
	gender CHAR(1) COMMENT '性别',
	age TINYINT UNSIGNED COMMENT '年龄',
	idcard CHAR(18) COMMENT '身份证号',
	entrydate DATE COMMENT '入职时间'
) COMMENT '员工表';

  • 添加字段
ALTER TABLE emp ADD nickname VARCHAR(20) COMMENT '昵称';

  • 修改字段(类型)
ALTER TABLE employee MODIFY workno VARCHAR(20) COMMENT '工号';
  • 修改字段(类型和名称)
ALTER TABLE emp CHANGE nickname username VARCHAR(30) COMMENT '用户名';

  • 删除字段
ALTER TABLE emp DROP username;

  • 修改表名
ALTER TABLE emp RENAME TO employee;

  • 删除表
CREATE TABLE test_1(id INT);
DROP TABLE IF EXISTS test_1;
  • 删除表内的数据,保留表的结构
TRUNCATE TABLE employee;

2.DML


2.1.添加数据


INSERT INTO employee ( id, workno, name, gender, age, idcard, entrydate ) 
	VALUES ( 1, '1', 'ItCast', '男', 10, '123456789012345678', '2000-01-01' );
INSERT INTO employee
	VALUES ( 2, '2', '张无忌', '男', 18, '123456789012345678', '2005-05-02' );
INSERT INTO employee
	VALUES
	( 3, '3', '韦一笑', '男', 33, '123456789012345678', '1992-09-02' ),
	( 4, '4', '赵敏', '女', 18, '123456789012345678', '2005-01-01' );
INSERT INTO employee ( id, NAME ) VALUES ( 99, '测试者1号' );

2.2.更新数据


  • 修改 id 为 1 的数据,将 name 修改为 ItHeiMa
UPDATE employee SET NAME = 'ItHeiMa' WHERE id = 1;
  • 修改 id 为 1 的数据,将 name 修改为 小昭,gender 修改为 女
UPDATE employee SET NAME = '小昭', gender = '女' WHERE id = 1;
  • 将所有员工的入职日期修改为 2008-08-08
UPDATE employee SET entrydate = '2008-08-08';

2.3.删除数据


DELETE FROM employee WHERE gender = '女';
DELETE FROM employee;

3.DQL


3.1.数据准备


DROP TABLE IF EXISTS employee;
CREATE TABLE emp (
	id INT COMMENT '编号',
	workno VARCHAR ( 10 ) COMMENT '工号',
	name VARCHAR ( 10 ) COMMENT '姓名',
	gender CHAR ( 1 ) COMMENT '性别',
	age TINYINT UNSIGNED COMMENT '年龄',
	idcard CHAR ( 18 ) COMMENT '身份证号',
	workaddress VARCHAR ( 50 ) COMMENT '工作地址',
	entrydate date COMMENT '入职时间' 
) COMMENT '员工表';
INSERT INTO emp ( id, workno, name, gender, age, idcard, workaddress, entrydate )
	VALUES ( 1, '00001', '柳岩666', '女', 20, '123456789012345678', '北京', '2000-01-01' );

INSERT INTO emp ( id, workno, name, gender, age, idcard, workaddress, entrydate )
	VALUES ( 2, '00002', '张无忌', '男', 18, '123456789012345670', '北京', '2005-09-01' );

INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (3, '00003', '韦一笑', '男', 38, '123456789712345670', '上海', '2005-08-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (4, '00004', '赵敏', '女', 18, '123456757123845670', '北京', '2009-12-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (5, '00005', '小昭', '女', 16, '123456769012345678', '上海', '2007-07-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (6, '00006', '杨逍', '男', 28, '12345678931234567X', '北京', '2006-01-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (7, '00007', '范瑶', '男', 40, '123456789212345670', '北京', '2005-05-01');

INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (8, '00008', '黛绮丝', '女', 38, '123456157123645670', '天津', '2015-05-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (9, '00009', '范凉凉', '女', 45, '123156789012345678', '北京', '2010-04-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (10, '00010', '陈友谅', '男', 53, '123456789012345670', '上海', '2011-01-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (11, '00011', '张士诚', '男', 55, '123567897123465670', '江苏', '2015-05-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (12, '00012', '常遇春', '男', 32, '123446757152345670', '北京', '2004-02-01');

INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (13, '00013', '张三丰', '男', 88, '123656789012345678', '江苏', '2020-11-01');

INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (14, '00014', '灭绝', '女', 65, '123456719012345670', '西安', '2019-05-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (15, '00015', '胡青牛', '男', 70, '12345674971234567X', '西安', '2018-04-01');
	
INSERT INTO emp (id, workno, name, gender, age, idcard, workaddress, entrydate)
	VALUES (16, '00016', '周芷若', '女', 18, null, '北京', '2012-06-01');

在这里插入图片描述


在这里插入图片描述


3.2.基础查询


SELECT name, workno, age FROM emp;
SELECT * FROM emp;
SELECT workaddress as '工作地址' FROM emp;
SELECT DISTINCT workaddress as '工作地址' FROM emp;

3.3.条件查询


SELECT * FROM emp WHERE age = 88;
SELECT * FROM emp WHERE age < 20;
SELECT * FROM emp WHERE age <= 20;

SELECT * FROM emp WHERE idcard IS NULL;
SELECT * FROM emp WHERE idcard IS NOT NULL;

SELECT * FROM emp WHERE age != 88;
SELECT * FROM emp WHERE age <> 88;

SELECT * FROM emp WHERE age >= 15 && age <= 20;
SELECT * FROM emp WHERE age >= 15 AND age <= 20;
SELECT * FROM emp WHERE age BETWEEN 15 AND 20;

SELECT * FROM emp WHERE gender = '女' AND age < 25;

SELECT * FROM emp WHERE age = 18 OR age = 20 OR age =40;
SELECT * FROM emp WHERE age IN(18,20,40);

SELECT * FROM emp WHERE NAME LIKE '__';

SELECT * FROM emp WHERE idcard LIKE '%X';
SELECT * FROM emp WHERE idcard LIKE '_________________X';

3.4.聚合查询(聚合函数)


SELECT COUNT(*) FROM emp; -- 统计的是总记录数
SELECT COUNT(idcard) FROM emp; -- 统计的是 idcard 字段不为 null 的记录数

对于 count 聚合函数,统计符合条件的总记录数,还可以通过 count(数字/字符串) 的形式进行统计查询

SELECT COUNT(1) FROM emp;

SELECT AVG(age) FROM emp;
SELECT MAX(age) FROM emp;
SELECT MIN(age) FROM emp;
SELECT SUM(age) FROM emp WHERE workaddress = '西安';

3.5.分组查询


  • 语法
    • SELECT 字段列表 FROM 表名 [ WHERE 条件 ] GROUP BY 分组字段名 [ HAVING 分组后的过滤条件 ];
  • wherehaving 的区别
    • 执行时机不同:where 是分组之前进行过滤,不满足 where 条件不参与分组;having 是分组后对结果进行过滤。
    • 判断条件不同:where 不能对聚合函数进行判断,而 having 可以。
  • 注意事项
    • 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
    • 执行顺序:where > 聚合函数 > having
    • 支持多字段分组, 具体语法为 group by columnA, columnB

  • 根据性别分组,统计男性和女性数量(只显示分组数量,不显示哪个是男哪个是女)
SELECT COUNT(*) FROM emp GROUP BY gender;
  • 根据性别分组,统计男性和女性数量
SELECT gender, COUNT(*) FROM emp GROUP BY gender;
  • 根据性别分组,统计男性和女性的平均年龄
SELECT gender, AVG(age) FROM emp GROUP BY gender;
  • 年龄小于 45,并根据工作地址分组
SELECT workaddress, COUNT(*) FROM emp WHERE age < 45 GROUP BY workaddress;
  • 年龄小于 45,并根据工作地址分组,获取员工数量大于等于 3 的工作地址
SELECT workaddress, COUNT(*) address_count FROM emp WHERE age < 45 GROUP BY workaddress HAVING address_count >= 3;

3.6.排序查询


SELECT * FROM emp ORDER BY age ASC;
SELECT * FROM emp ORDER BY age;

  • 两字段排序,根据年龄升序排序,入职时间降序排序
SELECT * FROM emp ORDER BY age ASC, entrydate DESC;

3.7.分页查询


SELECT * FROM emp LIMIT 0,10;
SELECT * FROM emp LIMIT 10;

  • 查询第 2 页员工数据, 每页展示 10 条记录 --------> 第一个参数:(页码-1)*页展示记录数
SELECT * FROM emp LIMIT 10, 10;

3.8.案例


  • 查询年龄为 20,21,22,23 岁的女性员工信息。
SELECT * FROM emp WHERE gender ='女' AND age IN(20,21,22,23);

  • 查询性别为 男 ,并且年龄在 20-40 岁(包括左右边界)以内的姓名为三个字的员工。
SELECT * FROM emp WHERE gender ='男' AND age BETWEEN 20 AND 40 AND name LIKE '___';

  • 统计员工表中, 年龄小于 60 岁的 , 男性员工和女性员工的人数。
SELECT gender, COUNT(*) FROM emp WHERE age < 60 GROUP BY gender;

  • 查询所有年龄小于等于 35 岁员工的姓名和年龄,并对查询结果按年龄升序排序,如果年龄相同按入职时间降序排序。
SELECT name, age FROM emp WHERE age <= 35 ORDER BY age ASC , entrydate DESC;

  • 查询性别为男,且年龄在 20-40 岁(含)以内的前 5 个员工信息,对查询的结果按年龄升序排序,年龄相同按入职时间升序排序。
SELECT * FROM emp WHERE gender = '男' AND age BETWEEN 20 AND 40 ORDER BY age ASC, entrydate ASC LIMIT 5 ;

4.DCL


4.1.管理用户


  • 创建用户 itcast,只能够在当前主机 localhost 访问,密码 123456
CREATE USER 'itcast'@'localhost' IDENTIFIED BY '123456';
  • 创建用户 heima,可以在任意主机访问该数据库,密码 123456
CREATE USER 'heima'@'%' IDENTIFIED BY '123456';
  • 修改用户 heima 的访问密码为 1234
ALTER USER 'heima'@'%' IDENTIFIED WITH mysql_native_password BY '1234';
  • 删除 itcast@localhost 用户
DROP USER 'itcast'@'localhost';

4.2.权限控制


SHOW GRANTS FOR 'heima'@'%';
GRANT ALL ON itcast.* TO 'heima'@'%';
REVOKE ALL ON itcast.* FROM 'heima'@'%';

5.函数


5.1.字符串函数


  • 拼接
SELECT CONCAT('Hello', 'World');
  • 小写
SELECT LOWER('Hello');
  • 大写
SELECT UPPER('Hello');
  • 左填充
SELECT LPAD('01', 5, '-');
  • 右填充
SELECT RPAD('01', 5, '-');
  • 去除空格
SELECT TRIM(' Hello World ');
  • 切片(注意:该函数的起始索引为 1)
SELECT SUBSTRING('Hello World', 1, 5);

  • 案例:由于业务需求变更,企业员工的工号,统一为 5 位数,目前不足 5 位数的全部在前面补 0。

比如: 1 号员工的工号应该为 00001。

UPDATE emp SET workno = LPAD(workno, 5, '0');

5.2.数值函数


  • 向上取整
SELECT CEIL(1.1);
  • 向下取整
SELECT FLOOR(1.9);
  • 取模
SELECT MOD(7,4);
  • 获取随机数
SELECT RAND();
  • 四舍五入
SELECT ROUND(2.344,2);

  • 案例:通过数据库的函数,生成一个六位数的随机验证码。
  • 思路:
    • 获取随机数可以通过 rand() 函数,但是获取出来的随机数是在 0-1 之间的
    • 所以可以在其基础上乘以 1000000,然后舍弃小数部分,如果长度不足 6 位,补0
SELECT LPAD(ROUND(RAND()*1000000 , 0), 6, '0');

5.3.日期函数


  1. curdate:当前日期
SELECT CURDATE();
  1. curtime:当前时间
SELECT CURTIME();
  1. now:当前日期和时间
SELECT NOW();

  1. YEARMONTHDAY:当前年、月、日
SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());

  1. date_add:增加指定的时间间隔
SELECT DATE_ADD(NOW(), INTERVAL 70 YEAR );
  1. datediff:获取两个日期相差的天数
SELECT DATEDIFF('2021-12-01', '2021-10-01');

  • 案例:查询所有员工的入职天数,并根据入职天数倒序排序。
  • 思路: 入职天数,就是通过 当前日期 - 入职日期,所以需要使用 datediff 函数来完成。
SELECT name, DATEDIFF(CURDATE(), entrydate) AS 'entrydays' FROM emp ORDER BY entrydays DESC;

5.4.流程函数


  • IF(value , t , f):如果 value 为 true,则返回 t,否则返回 f
SELECT IF(FALSE, 'Ok', 'Error');

  • IFNULL(value1 , value2):如果 value1 不为空,返回 value1,否则返回 value2
SELECT IFNULL('Ok','Default');
SELECT IFNULL('','Default');
SELECT IFNULL(NULL,'Default');

  • case when then else end

    • CASE WHEN [ val1 ] THEN [ res1 ] … ELSE [ default ] END
      • 如果 val1 为 true,返回 res1,… 否则返回 default 默认值
    • CASE [ expr ] WHEN [ val1 ] THEN [ res1 ] … ELSE [ default ] END
      • 如果 expr 的值等于 val1,返回 res1,… 否则返回 default 默认值
  • 例如:查询 emp 表的员工姓名和工作地址 (北京/上海 ----> 一线城市;其他 ----> 二线城市)

    SELECT name,
    	( CASE workaddress WHEN '北京' THEN '一线城市' WHEN '上海' THEN '一线城市' ELSE '二线城市' END ) AS '一线/二线' 
    FROM emp;
    

在测试案例之前,做一些数据准备

CREATE TABLE score(
	id INT COMMENT 'ID',
	NAME VARCHAR(20) COMMENT '姓名',
	math INT COMMENT '数学',
	english INT COMMENT '英语',
	chinese INT COMMENT '语文'
) COMMENT '学员成绩表';
INSERT INTO score 
	VALUES 
		(1, 'Tom', 67, 88, 95),
		(2, 'Rose' , 23, 66, 90),
		(3, 'Jack', 56, 98, 76);
  • 案例:统计班级各个学员的成绩,展示的规则如下
    • 学生成绩 >= 85:优秀
    • 学生成绩 >= 60:及格
    • 学生成绩 < 60:不及格
SELECT
	id,
	name,
	( CASE WHEN math >= 85 THEN '优秀' WHEN math >= 60 THEN '及格' ELSE '不及格' END ) '数学',
	( CASE WHEN english >= 85 THEN '优秀' WHEN english >= 60 THEN '及格' ELSE '不及格' END ) '英语',
	( CASE WHEN chinese >= 85 THEN '优秀' WHEN chinese >= 60 THEN '及格' ELSE '不及格' END ) '语文' 
FROM
	score;

6.约束


6.1.常用约束


  • 案例要求
字段名字段含义字段类型约束条件约束关键字
idID 唯一标识int主键,并且自动增长PRIMARY KEY,AUTO_INCREMENT
name姓名varchar(10)不为空,并且唯一NOT NULL , UNIQUE
age年龄int大于 0,并且小于等于 120CHECK
status状态char(1)如果没有指定该值,默认为 1DEFAULT
gender性别char(1)
CREATE TABLE USER(
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR (10) NOT NULL UNIQUE,
  age INT CHECK (age > 0 AND age < 120),
  status CHAR(1) DEFAULT '1',
  gender CHAR(1)
);

6.2.外键约束


6.2.1.数据准备


CREATE TABLE dept(
	id INT AUTO_INCREMENT COMMENT 'ID' PRIMARY KEY,
	NAME VARCHAR(50) NOT NULL COMMENT '部门名称'
)COMMENT '部门表';
INSERT INTO dept (id, NAME) VALUES (1, '研发部'), (2, '市场部'),(3, '财务部'), (4,'销售部'), (5, '总经办');
CREATE TABLE emp(
	id INT AUTO_INCREMENT COMMENT 'ID' PRIMARY KEY,
	NAME VARCHAR(50) NOT NULL COMMENT '姓名',
	age INT COMMENT '年龄',
	job VARCHAR(20) COMMENT '职位',
	salary INT COMMENT '薪资',
	entrydate DATE COMMENT '入职时间',
	managerid INT COMMENT '直属领导ID',
	dept_id INT COMMENT '部门ID'
)COMMENT '员工表';
INSERT INTO emp (id, NAME, age, job,salary, entrydate, managerid, dept_id)
	VALUES
		(1, '金庸', 66, '总裁',20000, '2000-01-01', NULL,5),
		(2, '张无忌', 20,'项目经理',12500, '2005-12-05', 1,1),
		(3, '杨逍', 33, '开发', 8400,'2000-11-03', 2,1),
		(4, '韦一笑', 48, '开发',11000, '2002-02-05', 2,1),
		(5, '常遇春', 43, '开发',10500, '2004-09-07', 3,1),
		(6, '小昭', 19, '程序员鼓励师',6600, '2004-10-12', 2,1);

6.2.2.添加外键


ALTER TABLE emp 
	ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY (dept_id) REFERENCES dept(id);

6.2.3.外键删除/更新行为


ALTER TABLE emp 
	ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY ( dept_id ) REFERENCES dept ( id ) 
	ON UPDATE CASCADE 
	ON DELETE CASCADE;

ALTER TABLE emp 
	ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY ( dept_id ) REFERENCES dept ( id ) 
	ON UPDATE SET NULL 
	ON DELETE SET NULL;

7.多表查询


7.1.数据准备


7.1.1.多对多


在这里插入图片描述


CREATE TABLE student(
	id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
	name VARCHAR(10) COMMENT '姓名',
	no VARCHAR(10) COMMENT '学号'
) COMMENT '学生表';
INSERT INTO student 
	VALUES 
		(NULL, '黛绮丝', '2000100101'),
		(NULL, '谢逊','2000100102'),
		(NULL, '殷天正', '2000100103'),
		(NULL, '韦一笑', '2000100104');

CREATE TABLE course(
	id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
	name VARCHAR(10) COMMENT '课程名称'
) COMMENT '课程表';
INSERT INTO course 
	VALUES (NULL, 'Java'), (NULL, 'PHP'), (NULL , 'MySQL') ,(NULL, 'Hadoop');

CREATE TABLE student_course(
	id INT AUTO_INCREMENT COMMENT '主键' PRIMARY KEY,
	studentid INT NOT NULL COMMENT '学生ID',
	courseid INT NOT NULL COMMENT '课程ID',
	CONSTRAINT fk_courseid FOREIGN KEY (courseid) REFERENCES course (id),
	CONSTRAINT fk_studentid FOREIGN KEY (studentid) REFERENCES student (id)
)COMMENT '学生课程中间表';
INSERT INTO student_course 
	VALUES (NULL,1,1),(NULL,1,2),(NULL,1,3),(NULL,2,2),(NULL,2,3),(NULL,3,4);

7.1.2.一对一


在这里插入图片描述


CREATE TABLE tb_user(
	id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
	NAME VARCHAR(10) COMMENT '姓名',
	age INT COMMENT '年龄',
	gender CHAR(1) COMMENT '1: 男 , 2: 女',
	phone CHAR(11) COMMENT '手机号'
) COMMENT '用户基本信息表';
INSERT INTO tb_user(id, NAME, age, gender, phone) 
	VALUES
		(NULL,'黄渤',45,'1','18800001111'),
		(NULL,'冰冰',35,'2','18800002222'),
		(NULL,'码云',55,'1','18800008888'),
		(NULL,'李彦宏',50,'1','18800009999');

CREATE TABLE tb_user_edu(
	id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
	degree VARCHAR(20) COMMENT '学历',
	major VARCHAR(50) COMMENT '专业',
	primaryschool VARCHAR(50) COMMENT '小学',
	middleschool VARCHAR(50) COMMENT '中学',
	university VARCHAR(50) COMMENT '大学',
	userid INT UNIQUE COMMENT '用户ID',
	CONSTRAINT fk_userid FOREIGN KEY (userid) REFERENCES tb_user(id)
) COMMENT '用户教育信息表';
INSERT INTO tb_user_edu(id, degree, major, primaryschool, middleschool, university, userid) 
	VALUES
		(NULL,'本科','舞蹈','静安区第一小学','静安区第一中学','北京舞蹈学院',1),
		(NULL,'硕士','表演','朝阳区第一小学','朝阳区第一中学','北京电影学院',2),
		(NULL,'本科','英语','杭州市第一小学','杭州市第一中学','杭州师范大学',3),
		(NULL,'本科','应用数学','阳泉第一小学','阳泉区第一中学','清华大学',4);

7.1.3.一对多


在这里插入图片描述


删除之前 emp,dept 表的测试数据。

执行如下脚本,创建 emp 表与 dept 表并插入测试数据。


CREATE TABLE dept(
	id INT AUTO_INCREMENT COMMENT 'ID' PRIMARY KEY,
	name VARCHAR(50) NOT NULL COMMENT '部门名称'
)COMMENT '部门表';
INSERT INTO dept (id, name) 
	VALUES (1, '研发部'), (2, '市场部'),(3, '财务部'), (4,'销售部'), (5, '总经办'), (6, '人事部');

CREATE TABLE emp(
	id INT AUTO_INCREMENT COMMENT 'ID' PRIMARY KEY,
	name VARCHAR(50) NOT NULL COMMENT '姓名',
	age INT COMMENT '年龄',
	job VARCHAR(20) COMMENT '职位',
	salary INT COMMENT '薪资',
	entrydate DATE COMMENT '入职时间',
	managerid INT COMMENT '直属领导ID',
	dept_id INT COMMENT '部门ID'
)COMMENT '员工表';
ALTER TABLE emp 
	ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY (dept_id) REFERENCES dept(id);
INSERT INTO emp (id, NAME, age, job,salary, entrydate, managerid, dept_id)
	VALUES
		(1, '金庸', 66, '总裁',20000, '2000-01-01', NULL,5),
		(2, '张无忌', 20, '项目经理',12500, '2005-12-05', 1,1),
		(3, '杨逍', 33, '开发', 8400,'2000-11-03', 2,1),
		(4, '韦一笑', 48, '开发',11000, '2002-02-05', 2,1),
		(5, '常遇春', 43, '开发',10500, '2004-09-07', 3,1),
		(6, '小昭', 19, '程序员鼓励师',6600, '2004-10-12', 2,1),
		(7, '灭绝', 60, '财务总监',8500, '2002-09-12', 1,3),
		(8, '周芷若', 19, '会计',4800, '2006-06-02', 7,3),
		(9, '丁敏君', 23, '出纳',5250, '2009-05-13', 7,3),
		(10, '赵敏', 20, '市场部总监',12500, '2004-10-12', 1,2),
		(11, '鹿杖客', 56, '职员',3750, '2006-10-03', 10,2),
		(12, '鹤笔翁', 19, '职员',3750, '2007-05-09', 10,2),
		(13, '方东白', 19, '职员',5500, '2009-02-12', 10,2),
		(14, '张三丰', 88, '销售总监',14000, '2004-10-12', 1,4),
		(15, '俞莲舟', 38, '销售',4600, '2004-10-12', 14,4),
		(16, '宋远桥', 40, '销售',4600, '2004-10-12', 14,4),
		(17, '陈友谅', 42, NULL,2000, '2011-10-12', 1,NULL);

7.2.连接查询


7.2.1.内连接


查询每一个员工的姓名,及关联的部门的名称(隐式内连接实现)

  • 表结构:emp , dept
  • 连接条件:emp.dept_id = dept.id
SELECT emp.name , dept.name FROM emp , dept WHERE emp.dept_id = dept.id;
  • 为每一张表起别名,简化 SQL 编写
SELECT e.name, d.name FROM emp e , dept d WHERE e.dept_id = d.id;

查询每一个员工的姓名 , 及关联的部门的名称(显式内连接实现)

  • INNER JOIN …ON …
  • 表结构:emp , dept
  • 连接条件:emp.dept_id = dept.id
SELECT e.name, d.name FROM emp e INNER JOIN dept d ON e.dept_id = d.id;
  • 为每一张表起别名,简化 SQL 编写
SELECT e.name, d.name FROM emp e JOIN dept d ON e.dept_id = d.id;

7.2.2.外连接


查询 emp 表的所有数据, 和对应的部门信息(左外连接)

由于需求中提到,要查询 emp 的所有数据,所以是不能内连接查询的,需要考虑使用外连接查询。

  • 表结构: emp, dept
  • 连接条件: emp.dept_id = dept.id
SELECT e.*, d.name FROM emp e LEFT OUTER JOIN dept d ON e.dept_id = d.id;
SELECT e.*, d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id;

查询 dept 表的所有数据, 和对应的员工信息(右外连接)

由于需求中提到,要查询 dept 表的所有数据,所以是不能内连接查询的,需要考虑使用外连接查询。

  • 表结构:emp, dept
  • 连接条件:emp.dept_id = dept.id
SELECT d.*, e.* FROM emp e RIGHT OUTER JOIN dept d ON e.dept_id = d.id;

左外连接和右外连接是可以相互替换的。

只需要调整在连接查询时 SQL 中,表结构的先后顺序就可以了。

SELECT d.*, e.* FROM dept d LEFT OUTER JOIN emp e ON e.dept_id = d.id;

7.2.3.自连接


  • 案例:查询员工 及其 所属领导的名字(表结构:emp)
SELECT a.name , b.name FROM emp a , emp b WHERE a.managerid = b.id;

  • 查询所有员工 emp 及其领导的名字 emp , 如果员工没有领导, 也需要查询出来(表结构:emp a , emp b)
SELECT a.name '员工', b.name '领导' FROM emp a LEFT JOIN emp b ON a.managerid = b.id;

7.3.联合查询


将薪资低于 5000 的员工 , 和 年龄大于 50 岁的员工全部查询出来。

当前对于这个需求,我们可以直接使用多条件查询,使用逻辑运算符 or 连接即可。那这里呢?

  • 我们也可以通过 union / union all 来联合查询。

  • union all 查询出来的结果,仅仅进行简单的合并,并未去重。
SELECT * FROM emp WHERE salary < 5000
UNION ALL
SELECT * FROM emp WHERE age > 50;

  • union 联合查询,会对查询出来的结果进行去重处理。
SELECT * FROM emp WHERE salary < 5000
UNION
SELECT * FROM emp WHERE age > 50;

7.4.子查询


SQL 语句中嵌套 SELECT 语句,称为嵌套查询,又称子查询。

SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2 );

子查询外部的语句可以是 INSERT / UPDATE / DELETE / SELECT 的任何一个。


7.4.1.标量子查询


子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。


  • 案例:查询 “销售部” 的所有员工信息

完成这个需求时,我们可以将需求分解为两步:

  1. 查询 “销售部” 部门 ID

    SELECT id FROM dept WHERE NAME = '销售部';
    
  2. 根据 “销售部” 部门 ID, 查询员工信息

    SELECT * FROM emp WHERE dept_id = (SELECT id FROM dept WHERE NAME = '销售部');
    

  • 案例:查询在 “方东白” 入职时间之后的员工信息

完成这个需求时,我们可以将需求分解为两步:

  1. 查询 方东白 的入职日期

    SELECT entrydate FROM emp WHERE NAME = '方东白';
    
  2. 查询指定入职日期之后入职的员工信息

    SELECT * FROM emp WHERE entrydate > (SELECT entrydate FROM emp WHERE NAME = '方东白');
    

7.4.2.列子查询


子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。


常用的操作符:INNOT INANYSOMEALL


  • 案例:查询 “销售部” 和 “市场部” 的所有员工信息

分解为以下两步

  1. 查询 “销售部” 和 “市场部” 的部门 ID

    SELECT id FROM dept WHERE name = '销售部' OR name = '市场部';
    
  2. 根据部门 ID,查询员工信息

    SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME = '销售部' OR NAME = '市场部');
    

  • 案例:查询比 财务部 所有人工资都高的员工信息

分解为以下两步

  1. 查询所有 财务部 人员工资

    SELECT id FROM dept WHERE NAME = '财务部';
    
    SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE NAME = '财务部');
    
  2. 比 财务部 所有人工资都高的员工信息

    SELECT * FROM emp WHERE salary > ALL (
    	SELECT salary FROM emp WHERE dept_id =(SELECT id FROM dept WHERE NAME = '财务部') 
     );
    

  • 案例:查询比研发部其中任意一人工资高的员工信息

分解为以下两步

  1. 查询研发部所有人工资

    SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE NAME = '研发部');
    
  2. 比研发部其中任意一人工资高的员工信息

    SELECT * FROM emp WHERE salary > ANY ( 
    		SELECT salary FROM emp WHERE dept_id =( 
    				SELECT id FROM dept WHERE NAME = '研发部'
    			) 
    	);
    

7.4.3.行子查询


子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。


常用的操作符:=<> INNOT IN


  • 案例:查询与 “张无忌” 的薪资及直属领导相同的员工信息

这个需求同样可以拆解为两步进行:

  1. 查询 “张无忌” 的薪资及直属领导

    SELECT salary, managerid FROM emp WHERE NAME = '张无忌';
    
  2. 查询与 “张无忌” 的薪资及直属领导相同的员工信息

    SELECT * FROM emp WHERE (salary,managerid) = (SELECT salary, managerid FROM emp WHERE NAME = '张无忌');
    

7.4.4.表子查询


返回的结果是多行多列


常用操作符:IN


  • 案例: 查询与 “鹿杖客” , “宋远桥” 的职位和薪资相同的员工信息

分解为两步执行

  1. 查询 “鹿杖客” , “宋远桥” 的职位和薪资
SELECT job, salary FROM emp WHERE NAME = '鹿杖客' OR NAME = '宋远桥';
  1. 查询与 “鹿杖客” , “宋远桥” 的职位和薪资相同的员工信息
SELECT * FROM emp WHERE ( job, salary ) IN ( SELECT job, salary FROM emp WHERE NAME = '鹿杖客' OR NAME = '宋远桥' );

  • 案例: 查询入职日期是 “2006-01-01” 之后的员工信息,及其部门信息

分两步执行

  1. 入职日期是 “2006-01-01” 之后的员工信息
SELECT * FROM emp WHERE entrydate > '2006-01-01';
  1. 查询这部分员工,对应的部门信息
SELECT e.*, d.* FROM (SELECT * FROM emp WHERE entrydate > '2006-01-01') e LEFT JOIN dept d ON e.dept_id = d.id ;

7.5.多表查询案例


7.5.1.数据准备


CREATE TABLE salgrade(
	grade INT,
	losal INT,
	hisal INT
) COMMENT '薪资等级表';
INSERT INTO salgrade VALUES (1,0,3000);
INSERT INTO salgrade VALUES (2,3001,5000);
INSERT INTO salgrade VALUES (3,5001,8000);
INSERT INTO salgrade VALUES (4,8001,10000);
INSERT INTO salgrade VALUES (5,10001,15000);
INSERT INTO salgrade VALUES (6,15001,20000);
INSERT INTO salgrade VALUES (7,20001,25000);
INSERT INTO salgrade VALUES (8,25001,30000);

在这个案例中,我们主要运用上面所讲解的多表查询的语法,完成以下的 12 个需求即可。

这里主要涉及到的表就三张:emp 员工表、dept 部门表、salgrade 薪资等级表 。

在这里插入图片描述
在这里插入图片描述


7.5.2.题目需求


以下需求的实现方式可能会很多,SQL 写法也有很多,只要能满足我们的需求,查询出符合条件的记录即可。

根据需求,完成 SQL 语句的编写

  1. 查询员工的姓名、年龄、职位、部门信息。
  2. 查询年龄小于 30 岁的员工姓名、 年龄、职位、部门信息。
  3. 查询拥有 员工的部门 ID、部门名称。
  4. 查询所有年龄大于 40 岁 的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来。
  5. 查询所有员工的工资等级。
  6. 查询 "研发部"所有员工的信息及工资等级。
  7. 查询"研发部"员工的平均工资。
  8. 查询工资比 “灭绝” 高的员工信息。
  9. 查询比平均薪资高的员工信息。
  10. 查询低于本部门平均工资的员工信息。
  11. 查询所有的部门信息,并统计部门的员工人数。
  12. 查询所有学生的选课情况,展示出学生名称,学号,课程名称,

7.5.3.解答


以上需求的实现方式可能会很多,SQL 写法也有很多,只要能满足我们的需求,查询出符合条件的记录即可。

  • 题一:查询员工的姓名、年龄、职位、部门信息 (隐式内连接)
    • 表:emp , dept
    • 连接条件:emp.dept_id = dept.id
SELECT
	e.name, e.age, e.job, d.name
FROM
	emp e, dept d 
WHERE
	e.dept_id = d.id;

  • 题二:查询年龄小于 30 岁的员工的姓名、年龄、职位、部门信息(显式内连接)
    • 表:emp , dept
    • 连接条件:emp.dept_id = dept.id
SELECT 
	e.name , e.age , e.job , d.name 
FROM 
	emp e 
	INNER JOIN dept d ON e.dept_id = d.id 
WHERE 
	e.age < 30;

  • 题三:查询拥有员工的部门 ID、部门名称
    • 表:emp , dept
    • 连接条件:emp.dept_id = dept.id
SELECT DISTINCT
	d.id,
	d.name 
FROM
	emp e,
	dept d 
WHERE
	e.dept_id = d.id;

  • 题四:查询所有年龄大于40岁的员工, 及其归属的部门名称; 如果员工没有分配部门, 也需要展示出来(外连接)
    • 表:emp , dept
    • 连接条件:emp.dept_id = dept.id
SELECT
	e.*,
	d.`name`
FROM
	emp e
	LEFT JOIN dept d ON e.dept_id = d.id 
WHERE
	e.age > 40;

  • 题五:查询所有员工的工资等级
    • 表:emp , salgrade
    • 连接条件:emp.salary >= salgrade.losal and emp.salary <= salgrade.hisal
-- 解法一
SELECT 
	e.* , s.grade , s.losal, s.hisal 
FROM 
	emp e , salgrade s 
WHERE 
	e.salary >= s.losal 
	AND e.salary <= s.hisal;
-- 解法二
SELECT 
	e.* , s.grade , s.losal, s.hisal 
FROM 
	emp e , salgrade s 
WHERE 
	e.salary BETWEEN s.losal AND s.hisal;

  • 题六:查询 “研发部” 所有员工的信息及 工资等级
    • 表: emp , salgrade , dept
    • 连接条件:emp.salary between salgrade.losal and salgrade.hisal , emp.dept_id = dept.id
    • 查询条件:dept.name = ‘研发部’
SELECT
	e.*, s.grade 
FROM
	emp e, dept d, salgrade s 
WHERE
	e.dept_id = d.id 
	AND ( e.salary BETWEEN s.losal AND s.hisal ) 
	AND d.NAME = '研发部';

  • 题七:查询 “研发部” 员工的平均工资
    • 表: emp , dept
    • 连接条件 : emp.dept_id = dept.id
SELECT
	AVG(e.salary)
FROM
	emp e,
	dept d 
WHERE
	e.dept_id = dept_id 
	AND d.name = '研发部';

  • 题八: 查询工资比 “灭绝” 高的员工信息。
    • 查询 “灭绝” 的薪资
    SELECT salary FROM emp WHERE name = '灭绝';
    
    • 查询比她工资高的员工数据
    SELECT
    	* 
    FROM
    	emp 
    WHERE
    	salary > ( SELECT salary FROM emp WHERE name = '灭绝' );
    

  • 题九:查询比平均薪资高的员工信息
    • 查询员工的平均薪资
    SELECT avg( salary ) FROM emp;
    
    • 查询比平均薪资高的员工信息
    SELECT
    	* 
    FROM
    	emp 
    WHERE
    	salary > ( SELECT avg( salary ) FROM emp );
    

  • 题十:查询低于本部门平均工资的员工信息

    • 查询指定部门平均薪资
    SELECT AVG( e1.salary ) FROM emp e1 WHERE e1.dept_id = 1;
    
    SELECT AVG( e2.salary ) FROM emp e1 WHERE e2.dept_id = 2;
    
    • 查询低于本部门平均工资的员工信息
    SELECT
    	* 
    FROM
    	emp e2 
    WHERE
    	e2.salary < ( SELECT AVG( e1.salary ) FROM emp e1 WHERE e1.dept_id = e2.dept_id );
    

  • 题十一:查询所有的部门信息, 并统计部门的员工人数
SELECT
	d.id, d.name,
	( SELECT COUNT(*) FROM emp e WHERE e.dept_id = d.id ) '人数'
FROM
	dept d;

在这里插入图片描述

  • 题十二:查询所有学生的选课情况, 展示出学生名称, 学号, 课程名称
    • 表:student , course , student_course
    • 连接条件:student.id = student_course.studentid , course.id = student_course.courseid
SELECT
	s.name, s.no, c.name
FROM
	student s,
	student_course sc,
	course c 
WHERE
	s.id = sc.studentid 
	AND sc.courseid = c.id;

8.事务


事务是一组操作的集合,它是一个不可分割的工作单位。

事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求。即这些操作要么同时成功,要么同时失败。


8.1.数据准备


DROP TABLE IF EXISTS account;
CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',
	NAME VARCHAR(10) COMMENT '姓名',
	money DOUBLE(10,2) COMMENT '余额'
) COMMENT '账户表';
INSERT INTO account(NAME, money) VALUES ('张三',2000), ('李四',2000);

8.2.基本操作


-- 手动开启事务
START TRANSACTION

-- 1. 查询张三余额
SELECT * FROM account WHERE NAME = '张三';

-- 2. 张三的余额减少 1000
UPDATE account SET money = money - 1000 WHERE NAME = '张三';

-- 3. 李四的余额增加 1000
UPDATE account SET money = money + 1000 WHERE NAME = '李四';

-- 如果正常执行完毕, 则提交事务
COMMIT;

-- 如果执行过程中报错, 则回滚事务
ROLLBACK;

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值