【MySQL】多表查询

  • ~2.48K 字
  1. 1. 多表关系
  2. 2. 多表查询
    1. 2.1. 分类
    2. 2.2. 内连接
    3. 2.3. 外连接
    4. 2.4. 自连接
    5. 2.5. 联合查询
    6. 2.6. 子查询
      1. 2.6.1. 分类
      2. 2.6.2. 标量子查询
      3. 2.6.3. 列子查询
      4. 2.6.4. 行子查询
      5. 2.6.5. 表子查询
      6. 2.6.6. 关联子查询

多表关系

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

  • 一对多/多对一:在多的一方建立外键,指向一的一方的主键
  • 多对多:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
  • 一对一:多用于单表拆分,在任意一方加入外键,关联另一方的主键,并设置外键为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;
赞助喵
非常感谢您的喜欢!
赞助喵