黑马MySQL数据库学习day03 级联 多表查询 连接和子查询

 1 /*
 2 存在外键的表
 3     删表限制:
 4         1.先删除从表,再删除主表。(不能直接删除主表,主表被从表引用,尽管实际可能还没有记录引用)
 5     建表限制:
 6         1.必须先建主表,再建从表(没有主表,从表无法建立外键关系)
 7 */
 8 DROP TABLE IF EXISTS employee;
 9 DROP TABLE IF EXISTS department;
10 
11 CREATE TABLE department(
12     id INT PRIMARY KEY,
13     name varchar(50) UNIQUE NOT NULL
14 );
15 -- 建表时,添加外键
16 CREATE TABLE employee(
17     id INT PRIMARY KEY,
18     name    varchar(50) NOT NULL,
19     dep_id    INT,
20     -- CONSTRAINT emp_dep_fk FOREIGN KEY(dep_id) REFERENCES department(id)
21     -- CONSTRAINT emp_dep_fk FOREIGN KEY(dep_id) REFERENCES department(id) ON DELETE CASCADE
22     -- CONSTRAINT emp_dep_fk FOREIGN KEY(dep_id) REFERENCES department(id) ON UPDATE CASCADE
23     CONSTRAINT emp_dep_fk FOREIGN KEY(dep_id) REFERENCES department(id) ON UPDATE CASCADE ON DELETE CASCADE
24 );
25 
26 INSERT INTO department(id, name)
27 VALUES
28 (1, '技术部'),
29 (2, '测试部');
30 
31 INSERT INTO employee(id, name, dep_id)
32 VALUES
33 (1, '刘备', 1),
34 (2, '孙权', 1),
35 (3, '曹操', 2),
36 (4, '大乔', 2),
37 (5, '小乔', 2);
38 
39 SHOW CREATE TABLE employee;
40 
41 -- 级联删除,解决记录被引用时,删除记录不方便。
42 -- bug点: 删除记录时,引用该记录的记录也被删除
43 DELETE FROM department where id = 1;
44 
45 -- 只想删除记录,不想删除引用该记录的记录。不应该用级联删除。先置null,清除引用,再删除记录。
46 UPDATE employee SET dep_id = NULL WHERE dep_id = 1;
47 DELETE FROM department where id = 1;
48 
49 
50 -- 级联更新,解决记录被引用时,更新记录不方便。
51 -- 更新记录时,引用该记录的记录也被更新
52 UPDATE department set id = 3 where id = 2;
级联
  1 /*
  2 多表查询:
  3 连接
  4         1.内连接
  5             表中符合连接条件的记录才会出现在结果中。
  6             方式:
  7                 SELECT 查询目标 FROM tb_name1, tb_name2,... WHERE 查询条件
  8                 SELECT 查询目标 FROM tb_name1 
  9                             [INNER] JOIN tb_name2 ON 查询条件
 10                             [INNER] JOIN tb_name3 ON 查询条件
 11                             ...
 12 
 13         2.外连接
 14             悬浮元组:不符合连接条件的记录。
 15             左外连接
 16                 查询出左表的全部数据,悬浮元组跟null值连接。
 17             SELECT 查询目标 FROM tb_name1 
 18                         LEFT JOIN tb_name2 ON 查询条件
 19                         LEFT JOIN tb_name3 ON 查询条件
 20                         ...
 21 
 22             右外连接
 23                 查询出右表的全部数据,悬浮元组跟null值连接。
 24             SELECT 查询目标 FROM tb_name1 
 25                         RIGHT JOIN tb_name2 ON 查询条件
 26                         RIGHT JOIN tb_name3 ON 查询条件
 27                         ...
 28 
 29             全外连接(MySQL不支持)
 30                 查询出左表和右表的全部数据,左表和右表的悬浮元组跟null值连接。
 31 
 32     注意特殊的数据:
 33         新成立的部门测试部,没有员工
 34         新入职的员工小白龙,没有部门
 35 */
 36 drop table if exists emp;
 37 drop table if exists dept;
 38 
 39 create table dept(
 40     id int primary key auto_increment,
 41     name varchar(20)
 42 );
 43 insert into dept (name) values ('开发部'),('市场部'),('财务部'),('测试部');
 44 # 创建员工表
 45 create table emp (
 46     id int primary key auto_increment,
 47     name varchar(10),
 48     gender char(1), -- 性别
 49     salary double, -- 工资
 50     join_date date, -- 入职日期
 51     dept_id int,
 52     foreign key (dept_id) references dept(id) -- 外键,关联部门表(部门表的主键)
 53 );
 54 insert into emp(name,gender,salary,join_date,dept_id) values('孙悟空','',7200,'2013-02-24',1);
 55 insert into emp(name,gender,salary,join_date,dept_id) values('猪八戒','',3600,'2010-12-02',2);
 56 insert into emp(name,gender,salary,join_date,dept_id) values('唐僧','',9000,'2008-08-08',2);
 57 insert into emp(name,gender,salary,join_date,dept_id) values('白骨精','',5000,'2015-10-07',3);
 58 insert into emp(name,gender,salary,join_date,dept_id) values('蜘蛛精','',4500,'2011-03-14',1);
 59 insert into emp(name,gender,salary,join_date,dept_id) values('小白龙','',3000,'2019-03-14',null);
 60 
 61 -- 连接查询帮助 help join
 62 
 63 -- 内连接不规范的写法,不容易阅读
 64 SELECT emp.id, emp.name, emp.gender, dept.name FROM emp , dept WHERE emp.dept_id = dept.id;
 65 
 66 -- 需求:查询员工和部门信息(不包括没有部门的员工)
 67 -- 内连接,隐式
 68 SELECT    
 69     t1.id, -- 员工id
 70     t1.name, -- 员工姓名
 71     t1.gender, -- 员工性别
 72     t2.name -- 部门名称
 73 FROM
 74     emp AS t1, -- 员工表
 75     dept AS t2 -- 部门表
 76 WHERE
 77     t1.dept_id = t2.id;
 78 
 79 -- 内连接,显式
 80 SELECT    
 81     t1.id, -- 员工id
 82     t1.name, -- 员工姓名
 83     t1.gender, -- 员工性别
 84     t2.name -- 部门名称
 85 FROM
 86     emp AS t1 -- 员工表
 87     JOIN dept AS t2 -- 部门表
 88 ON
 89     t1.dept_id = t2.id;
 90 
 91 -- 需求2:查询所有员工的信息(包括没有部门的员工)
 92 -- 方案一:左外连接
 93 SELECT    
 94     t1.id, -- 员工id
 95     t1.name, -- 员工姓名
 96     t1.gender, -- 员工性别
 97     t2.name -- 部门名称
 98 FROM
 99     emp AS t1 -- 员工表
100 LEFT JOIN
101     dept AS t2 -- 部门表
102 ON
103     t1.dept_id = t2.id;
104 
105 -- 方案二:右外连接
106 SELECT    
107     t1.id, -- 员工id
108     t1.name, -- 员工姓名
109     t1.gender, -- 员工性别
110     t2.name -- 部门名称
111 FROM
112     dept AS t2 -- 部门表
113 RIGHT JOIN
114     emp AS t1 -- 员工表
115 ON
116     t1.dept_id = t2.id;
连接
 1 /*
 2     子查询:
 3         1.子查询的结果是单行单列
 4             即,子查询的结果是一个值,可以参与运算。
 5         2.子查询的结果是多行单列
 6             即,子查询的结果是一列,可以使用IN运算符。
 7         3.子查询的结果是多行多列
 8             即,子查询的结果是表,可以像实体表一样参与查询
 9 
10     注意特殊的数据:
11         测试部,新建立的部门,没有员工
12         小白龙,新入职的员工,没有部门
13 */
14 drop table if exists emp;
15 drop table if exists dept;
16 
17 create table dept(
18     id int primary key auto_increment,
19     name varchar(20)
20 );
21 insert into dept (name) values ('开发部'),('市场部'),('财务部'),('测试部');
22 # 创建员工表
23 create table emp (
24     id int primary key auto_increment,
25     name varchar(10),
26     gender char(1), -- 性别
27     salary double, -- 工资
28     join_date date, -- 入职日期
29     dept_id int,
30     foreign key (dept_id) references dept(id) -- 外键,关联部门表(部门表的主键)
31 );
32 insert into emp(name,gender,salary,join_date,dept_id) values('孙悟空','',7200,'2013-02-24',1);
33 insert into emp(name,gender,salary,join_date,dept_id) values('猪八戒','',3600,'2010-12-02',1);
34 insert into emp(name,gender,salary,join_date,dept_id) values('唐僧','',9000,'2008-08-08',2);
35 insert into emp(name,gender,salary,join_date,dept_id) values('白骨精','',5000,'2015-10-07',3);
36 insert into emp(name,gender,salary,join_date,dept_id) values('蜘蛛精','',4500,'2011-03-14',1);
37 insert into emp(name,gender,salary,join_date,dept_id) values('小白龙','',3000,'2019-03-14',null);
38 
39 -- 需求1:查询工资最高的员工的信息(子查询的结果是一个值)
40 SELECT    
41     *
42 FROM
43     emp
44 WHERE -- 先查出最高的工资,再根据最高工资,查询员工信息。
45     salary = ( 
46             SELECT
47                 MAX(salary)
48             FROM 
49                 emp
50             );
51 
52 -- 需求2:查询市场部和财务部的员工信息(子查询的结果是一列,使用IN运算符)
53 SELECT
54     *
55 FROM
56     emp
57 WHERE
58     dept_id IN (
59                 SELECT
60                     id
61                 FROM
62                     dept
63                 WHERE
64                     name in('市场部', '财务部')
65                 );
66 
67 -- 需求3:查询2011年后入职的员工号,姓名,入职日期和其部门名称(查询的结果是一张表,可以像实体表一样参与查询)(注意:没有部门的员工不需要查询)
68 -- 子查询解法
69 SELECT
70     t1.id,
71     t1.name,
72     t1.join_date,
73     t2.name
74 FROM
75     (
76         SELECT
77             *
78         FROM
79             emp
80         WHERE
81             join_date >= '2011-01-01'
82     ) AS t1,
83     dept AS t2
84 WHERE
85     t1.dept_id = t2.id;
86 
87 -- 连接解法
88 SELECT
89     t1.id,
90     t1.name,
91     t1.join_date,
92     t2.name
93 FROM
94     emp AS t1,
95     dept AS t2
96 WHERE
97     t1.dept_id = t2.id
98     AND t1.join_date >= '2011-01-01';
子查询
  1 /*
  2     连接练习:
  3         bug点:
  4             1.给表起别名后,不能使用原名称
  5             2.分组对null值也看成一组。
  6         约定:
  7             每个员工都有部门和职务。
  8         特殊数据:
  9             财务部新成立,没有员工。
 10 */
 11 DROP TABLE if EXISTS emp;
 12 DROP TABLE if EXISTS dept;
 13 DROP TABLE if EXISTS job;
 14 DROP TABLE if EXISTS salarygrade;
 15 
 16 -- 部门表
 17 CREATE TABLE dept (
 18   id INT PRIMARY KEY PRIMARY KEY, -- 部门id
 19   dname VARCHAR(50), -- 部门名称
 20   loc VARCHAR(50) -- 部门所在地
 21 );
 22 
 23 -- 添加4个部门
 24 INSERT INTO dept(id,dname,loc) VALUES 
 25 (10,'教研部','北京'),
 26 (20,'学工部','上海'),
 27 (30,'销售部','广州'),
 28 (40,'财务部','深圳');
 29 
 30 
 31 
 32 -- 职务表,职务名称,职务描述
 33 CREATE TABLE job (
 34   id INT PRIMARY KEY,
 35   jname VARCHAR(20),
 36   description VARCHAR(50)
 37 );
 38 
 39 -- 添加4个职务
 40 INSERT INTO job (id, jname, description) VALUES
 41 (1, '董事长', '管理整个公司,接单'),
 42 (2, '经理', '管理部门员工'),
 43 (3, '销售员', '向客人推销产品'),
 44 (4, '文员', '使用办公软件');
 45 
 46 
 47 
 48 -- 员工表
 49 CREATE TABLE emp (
 50   id INT PRIMARY KEY, -- 员工id
 51   ename VARCHAR(50), -- 员工姓名
 52   job_id INT, -- 职务id
 53   mgr INT , -- 上级领导
 54   joindate DATE, -- 入职日期
 55   salary DECIMAL(7,2), -- 工资
 56   bonus DECIMAL(7,2), -- 奖金
 57   dept_id INT, -- 所在部门编号
 58   CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
 59   CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
 60 );
 61 
 62 -- 添加员工
 63 INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES 
 64 (1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),
 65 (1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),
 66 (1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),
 67 (1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
 68 (1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
 69 (1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
 70 (1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),
 71 (1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),
 72 (1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),
 73 (1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),
 74 (1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
 75 (1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
 76 (1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),
 77 (1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);
 78 
 79 
 80 
 81 -- 工资等级表
 82 CREATE TABLE salarygrade (
 83   grade INT PRIMARY KEY,   -- 级别
 84   losalary INT,  -- 最低工资
 85   hisalary INT -- 最高工资
 86 );
 87 
 88 -- 添加5个工资等级
 89 INSERT INTO salarygrade(grade,losalary,hisalary) VALUES 
 90 (1,7000,12000),
 91 (2,12010,14000),
 92 (3,14010,20000),
 93 (4,20010,30000),
 94 (5,30010,99990);
 95 
 96 -- 需求:(约定所有的员工都有部门和工作)
 97 
 98 -- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
 99 /*
100     分析:
101         1.员工编号,员工姓名,工资 emp表,职务名称,职务描述 job表
102         2.使用连接,连接条件是 emp.job_id = job.id
103 */
104 SELECT
105     t1.id, -- 员工编号
106     t1.ename, -- 员工姓名
107     t1.salary, -- 员工工资
108     t2.jname, -- 职务名称
109     t2.description -- 职务描述
110 FROM
111     emp AS t1 -- 员工表
112     JOIN
113         job    AS t2 -- 职务表
114     ON
115         t1.job_id = t2.id;
116 
117 
118 -- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
119 /*
120     分析:
121         1.员工编号,员工姓名,工资 emp表,职务名称,职务描述 job表,部门名称,部门位置 dept表
122         2.使用连接查询,连接条件 emp.job_id = job.id, emp.dept_id = dept.id
123 */
124 SELECT
125     t1.id, -- 员工编号
126     t1.ename, -- 员工姓名
127     t1.salary, -- 员工工资
128     t2.jname, -- 职务名称
129     t2.description, -- 职务描述
130     t3.dname, -- 部门名称
131     t3.loc -- 部门位置
132 FROM
133     emp AS t1 -- 员工表
134     JOIN 
135         job AS t2 -- 职务表
136     ON 
137         t1.job_id = t2.id
138     JOIN 
139         dept AS t3 -- 部门表
140     ON t1.dept_id = t3.id;
141 -- 3.查询员工姓名,工资,工资等级
142 /*
143     分析:
144         1.员工姓名,工资 emp表,工资等级 salarygrade表
145         2.通过连接,连接条件是工资在区间内。emp.salary >= salarygrade.losalary <= salarygrade.hisalary
146         简化 emp.salary BETWEEN salarygrade.losalary AND salarygrade.hisalary
147 */
148 SELECT
149     t1.ename, -- 员工姓名
150     t1.salary, -- 工资
151     t2.grade -- 工资等级
152 FROM
153     emp AS t1 -- 员工表
154     JOIN 
155         salarygrade AS t2 -- 薪资等级表
156     ON 
157         t1.salary BETWEEN t2.losalary AND t2.hisalary;
158 -- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
159 /*
160         分析:
161             1.员工姓名,工资 emp表,职务名称,职务描述 job表,部门名称,部门位置 dept表,工资等级 salarygrade表
162             2.需要进行连接,连接条件:
163                 emp.job_id = job.id, emp.dept_id = dept.id
164                 emp.salary BETWEEN salarygrade.losalary AND salarygrade.hisalary
165 */
166 SELECT
167     t1.ename, -- 员工姓名
168     t1.salary, -- 工资
169     t2.jname, -- 职务名称
170     t2.description, -- 职务描述
171     t3.dname, -- 部门名称
172     t3.loc, -- 部门位置
173     t4.grade -- 工资等级
174 FROM
175     emp AS t1 -- 员工表
176     JOIN    
177         job AS t2 -- 职务表
178     ON
179         t1.job_id = t2.id
180     JOIN
181         dept AS t3 -- 部门表
182     ON
183         t1.dept_id = t3.id
184     JOIN
185         salarygrade AS t4 -- 薪资等级表
186     ON
187         t1.salary BETWEEN t4.losalary AND t4.hisalary;
188         
189 -- 5.查询出部门编号、部门名称、部门位置、部门人数
190 /*
191     分析:
192         1.查询出部门编号、部门名称、部门位置 dept表、部门人数 emp表
193         2.员工表和部门表根据外键连接,左外连接进行连接,再统计部门人数
194     特殊数据:
195         财务部新成立,没有员工。
196 */
197 SELECT
198     t1.id,
199     t1.dname,
200     t1.loc,
201     count(t2.id) -- 不能写count(*),因为它会统计悬浮元组,悬浮元组表示没有员工,不应该被统计
202 FROM    
203     dept AS t1 -- 部门表
204     LEFT JOIN  
205         emp AS t2 -- 员工表
206     ON 
207         t1.id = t2.dept_id
208 GROUP BY
209     t1.id; -- 根据部门分组
210 
211 /*
212     典型错误代码:不能查询出人数为0的部门
213 */
214 SELECT
215     t1.id,
216     t1.dname,
217     t1.loc,
218     count(*)
219     -- count(*) count(t1.id) count(t2.id) 都得不到正确结果
220 FROM
221     dept AS t1,
222     emp AS t2
223 WHERE
224     t1.id = t2.dept_id
225 GROUP BY
226     t1.id;
227  
228 -- 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询
229 /*
230     分析:
231         1.所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询 emp表
232         2.自连接,连接条件 emp.mgr = emp.id,必须使用别名
233 */
234 SELECT
235     t1.ename AS ename, -- 员工姓名
236     t2.ename AS manager -- 直接上级
237 FROM -- 对员工表进行自连接,左外连接。
238     emp AS t1
239     LEFT JOIN
240         emp AS t2
241     ON
242         t1.mgr = t2.id;
连接练习

猜你喜欢

转载自www.cnblogs.com/mozq/p/10720924.html