mysql多表查询

    |     2016年11月3日   |   数据库   |     0 条评论   |    1737

多表查询是在多个有逻辑联系的表之间查询,逻辑关系主要指主外键:主表某字段的值取自另一表的字段集合。往主表插数据时,对应字段必须在关联表中存在(除非该字段可空),否则插不进去。实现方式是表连接或子查询。

假设有员工表和部门表(原文表名拼写为 deparment / employe,示例沿用):

-- 部门表
CREATE TABLE `deparment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `deparment_name` varchar(255) NOT NULL,
  `deparment_num` varchar(255) NOT NULL,
  `deparment_des` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `deparment` VALUES ('1', '人事部', 'A1001', '处理人事关系');
INSERT INTO `deparment` VALUES ('2', '财务部', 'B2001', '管理公司资产');
INSERT INTO `deparment` VALUES ('3', '行政部', 'C3001', '制订规章制度');

-- 员工表
CREATE TABLE `employe` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `d_id` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `fk` (`d_id`)
);

INSERT INTO `employe` VALUES ('5', '张三', '1');
INSERT INTO `employe` VALUES ('6', '李四', '1');
INSERT INTO `employe` VALUES ('7', '王二', '1');
INSERT INTO `employe` VALUES ('8', '麻子', '2');
INSERT INTO `employe` VALUES ('9', '小明', '3');

一、普通多表查询

语法:from 后面可以有很多表,表名用逗号隔开。这些表会做笛卡尔积,再用 where 过滤。

select 列1... from 表1, 表2... where condition...
mysql> select * from employe,deparment where employe.d_id = deparment.id;
+----+------+------+----+----------------+---------------+---------------+
| id | name | d_id | id | deparment_name | deparment_num | deparment_des |
+----+------+------+----+----------------+---------------+---------------+
|  5 | 张三 |    1 |  1 | 人事部         | A1001         | 处理人事关系  |
|  6 | 李四 |    1 |  1 | 人事部         | A1001         | 处理人事关系  |
|  7 | 王二 |    1 |  1 | 人事部         | A1001         | 处理人事关系  |
|  8 | 麻子 |    2 |  2 | 财务部         | B2001         | 管理公司资产  |
|  9 | 小明 |    3 |  3 | 行政部         | C3001         | 制订规章制度  |
+----+------+------+----+----------------+---------------+---------------+

二、内连接

select 列名1,... from 表1 inner join 表2 on 表1.列=表2.列 ... condition...

from 起表 1 与表 2 做匹配;每匹配一行,用 on 后条件判断是否成立,成立才放入临时结果。

mysql> SELECT * FROM employe AS e INNER JOIN deparment AS d ON e.d_id = d.id;
+----+------+------+----+----------------+---------------+---------------+
| id | name | d_id | id | deparment_name | deparment_num | deparment_des |
+----+------+------+----+----------------+---------------+---------------+
|  5 | 张三 |    1 |  1 | 人事部         | A1001         | 处理人事关系  |
|  6 | 李四 |    1 |  1 | 人事部         | A1001         | 处理人事关系  |
|  7 | 王二 |    1 |  1 | 人事部         | A1001         | 处理人事关系  |
|  8 | 麻子 |    2 |  2 | 财务部         | B2001         | 管理公司资产  |
|  9 | 小明 |    3 |  3 | 行政部         | C3001         | 制订规章制度  |
+----+------+------+----+----------------+---------------+---------------+

三、外连接

左外连接:左表所有记录都进结果集,无论右表有没有匹配。语法:select 列 from 表1 left outer join 表2 on 表1.列=表2.列,可继续 left outer join 表3。

mysql> SELECT e.name,d.deparment_name FROM employe AS e
    -> LEFT OUTER JOIN deparment AS d
    -> ON e.d_id = d.id;
+------+----------------+
| name | deparment_name |
+------+----------------+
| 张三 | 人事部         |
| 李四 | 人事部         |
| 王二 | 人事部         |
| 麻子 | 财务部         |
| 小明 | 行政部         |
| 小丽 | NULL           |
+------+----------------+

上例中“小丽”在员工表里,部门对不上,部门名就是 NULL。

右外连接:无论是否匹配,都返回右表全部记录。

mysql> SELECT e.name,d.deparment_name FROM employe AS e
    -> RIGHT OUTER JOIN deparment AS d
    -> ON e.d_id = d.id;
+------+----------------+
| name | deparment_name |
+------+----------------+
| 张三 | 人事部         |
| 李四 | 人事部         |
| 王二 | 人事部         |
| 麻子 | 财务部         |
| 小明 | 行政部         |
| NULL | 销售部         |
+------+----------------+

“销售部”在部门表里没有员工,员工名就是 NULL。MySQL 没有全外连接(FULL OUTER JOIN)。需要时可用 LEFT JOIN 与 RIGHT JOIN 再 UNION。

写法 保留哪边 匹配不上
FROM a, b WHERE a.x = b.x 只保留匹配行 相当于内连接
INNER JOIN … ON 只保留匹配行 不出现
LEFT OUTER JOIN 左表全部 右表列为 NULL
RIGHT OUTER JOIN 右表全部 左表列为 NULL

四、自连接

一张表与自己连接。例如查找每个员工的直接上级姓名:

mysql> CREATE TABLE people(
    -> id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> name varchar(50) NOT NULL,
    -> parent_id int DEFAULT 0);

mysql> SELECT * FROM people;
+----+--------+-----------+
| id | name   | parent_id |
+----+--------+-----------+
|  1 | 范总   |         0 |
|  2 | 何经理 |         1 |
|  3 | 麻主管 |         2 |
|  4 | 刘主管 |         2 |
|  5 | 李高级 |         3 |
|  6 | 王中级 |         3 |
|  7 | 张初级 |         4 |
+----+--------+-----------+

-- 查询刘主管的上级领导
mysql> SELECT s.name AS 姓名,f.name AS 领导 FROM people AS s
    -> INNER JOIN people AS f
    -> ON s.parent_id = f.id
    -> AND s.name='刘主管';
+--------+--------+
| 姓名   | 领导   |
+--------+--------+
| 刘主管 | 何经理 |
+--------+--------+

商城商品分类同样用父子 id 自连接:

mysql> select * from product;
+------------+----------------+-------------------+
| product_id | product_name   | product_parent_id |
+------------+----------------+-------------------+
|          1 | 天猫商品       |                 0 |
|          2 | 女装/内衣      |                 1 |
|          3 | 男装/运动户外  |                 1 |
|          4 | 家具建材       |                 1 |
|          5 | 汽车/配件/用品 |                 1 |
|          6 | 图书音像       |                 1 |
|          7 | 当季流行       |                 2 |
|          8 | 精选上装       |                 2 |
|          9 | 浪漫裙装       |                 2 |
|         10 | 女士下装       |                 2 |
|         11 | 成套家具       |                 4 |
|         12 | 客厅餐厅       |                 4 |
+------------+----------------+-------------------+

-- 查询女士下装分类的上级分类
mysql> SELECT s.product_name, f.product_name FROM product AS s
    -> INNER JOIN product AS f
    -> ON s.product_parent_id = f.product_id
    -> AND s.product_name='女士下装';
+--------------+--------------+
| product_name | product_name |
+--------------+--------------+
| 女士下装     | 女装/内衣    |
+--------------+--------------+

五、子查询

查询里面还可以有查询。外层叫主查询,内层叫子查询。子查询先运行,结果当作主查询的值。

  • 子查询返回单个值:用 =
  • 返回多行一列:用 IN
  • 返回一行多列:用 (a,b) IN ( … )
  • 返回多行多列:把条件拆开,将子查询得到的表再连接

条件拆得越简单越好,条件之间最好是包含关系,逻辑才通。也可以各种子查询并列,或一个是另一个的子查询。查询人事部所有员工姓名:

mysql> SELECT name AS 姓名 FROM employe AS e
    -> WHERE e.d_id = (SELECT id FROM deparment AS d WHERE d.deparment_name='人事部');
+------+
| 姓名 |
+------+
| 张三 |
| 李四 |
| 王二 |
+------+

注:笛卡尔积又叫直积。集合 A={a,b},B={0,1,2},则 A×B={(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可扩展到多个集合。若 A 是学生集合、B 是课程集合,A×B 表示所有可能的选课情况。

一句话总结:多表要么先笛卡尔积再用 WHERE/ON 收成匹配行(内连接),要么用左右外连接把某一侧整表留下;层级数据用自连接,单值过滤用子查询。

转载请注明来源:mysql多表查询
本文链接地址:https://ai.zhousir.top/?p=1752
回复 取消