红魔咖啡馆

头发越掉越多,头发越掉越少

0%

【MySQL】多表查询

多表关系

各个表之间存在着各种联系,一般分为三种,与他们的实现:

  • 一对多/多对一:在多的一方建立外键,指向一的一方的主键
  • 多对多:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
  • 一对一:多用于单表拆分,在任意一方加入外键,关联另一方的主键,并设置外键为UNIQUE

多表查询

  • SELECT * FROM a, b;可以查询到a表和b表的笛卡尔积,要想获得有效的查询,我们需要消除多余的笛卡尔积

  • SELECT * FROM a, b WHERE a.id = b.id;进行了等值连接,仅查询了两个表的关联数据

分类

  • 连接查询
    • 内连接:查询a,b表的交集部分数据
    • 左外连接:查询左表所有数据,以及两表交集部分数据
    • 右外连接:查询右表所有数据,以及两表交集部分数据
    • 自连接:当前表与自身的连接查询,必须使用别名

内连接

  • 隐式内连接:SELECT 字段列表 FROM 表1, 表2 WHERE 条件...;

  • 显式内连接:SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件...;

e.g. 查询员工表内员工姓名及关联的部门名称(分为员工表emp和部门表dept)

1
SELECT e.name, d.name FROM emp e JOIN dept d WHERE e.dept_id = d.id;

外连接

  • 左外连接:SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 连接条件...;
  • 右外连接:SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 连接条件...;

e.g.1 查询emp表的所有数据和对应的部门信息(dept表)

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

e.g.2 查询dept表的所有数据和对应的员工信息(emp表)

1
SELECT e.*, d.* FROM emp e RIGHT JOIN dept d ON e.dept_id = d.id;

自连接

SELECT 字段列表 FROM 表A 别名A JOIN 表B 别名B ON 条件...

自连接可以是内连接查询,也可以是外连接查询

e.g. 查询员工表内员工及其所属领导的名字(所属领导id和员工id在同一张表emp上)

这里我们要查询同一张表两次,把他当作两张表

1
SELECT a.name, b.name FROM emp a JOIN emp b WHERE a.managerid = b.id;

联合查询

把多次查询的结果合并起来,形成一个新的查询结果集

1
SELECT 字段列表 FROM 表A... UNION SELECT 字段列表 FROM 表A...;
  • UNION合并并去重
  • UNION ALL只会合并

条件:联合查询中多张表的列数、字段类型必须一致

子查询

嵌套SELECT语句,成为嵌套查询或子查询

外部语句可以是SELECT/INSERT/UPDATE/DELETE中的任意一个

分类

根据结果:

  • 标量子查询:子查询结果为单个值
  • 列子查询:子查询结果为一列
  • 行子查询:子查询结果为一行
  • 表子查询:子查询结果为多行多列

根据位置:

  • WHERE之后
  • FROM之后
  • SELECT之后

标量子查询

子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式

常用操作符:= > < >= <=

e.g. 将以下两个查询合并

1
2
SELECT id FROM dept WHERE name='销售部';
SELECT * FROM emp WHERE dept_id = 4;

可以得到

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

列子查询

子查询返回结果是一列(多行)

常用操作符:

e.g. 查询比研发部中任意一人工资高的员工信息

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

行子查询

子查询返回结果是一行(多列)

常用操作符:= <> IN NOT IN

e.g. 查询与李华薪资喝直属领导相同的员工信息

1
SELECT * FROM emp WHERE (salary, managerid) = (SELECT salary, managerid FROM emp WHERE name = '李华');

这里可以用括号括起多个条件,一一对应

表子查询

子查询返回结果是多行多列

常用操作:IN

e.g. 查询与张三和李四的职位和薪资相同的员工信息

1
SELECT * FROM emp WHERE (job, salary) IN (SELECT job, salary FROM emp WHERE name='张三' OR name='李四');

关联子查询

某些子查询中会引用外部查询中的列,与外部查询产生关联

没有关联的叫做非关联子查询

关联子查询对外查询中的每一行都会运行一次,有的数据库可能会对其优化

e.g. 查询所有部门信息,并统计部门员工人数

1
SELECT d.id, d.name, (SELECT COUNT(*) FROM emp e WHERE e.dept_id = d.id) '人数' FROM dept d;