博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
05-多表查询
阅读量:7223 次
发布时间:2019-06-29

本文共 13631 字,大约阅读时间需要 45 分钟。

多表查询

1.说明

  当存储时,相同数据出现多次决不是一件好事,这个因素是关系数据库设计的基础。关系表的设计就是要保证把信息分解成多个表,一类数据一个表,各表通过默写常用的值互相关联。

  分解数据为多个表能更有效地存储,更方便地处理,并且具有更大的可伸缩性。但这样就不能使用单条SELECT语句检索出数据。

  SQL最强大的功能之一就是能在数据检索查询的执行中连接(join)表。

常见术语:

  外键(foreign key)外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。

  可伸缩性(scale)能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好(sacle well)。

数据源

#建表create table department(id int,name varchar(20) );create table employee(id int primary key auto_increment,name varchar(20),sex enum('male','female') not null default 'male',age int,dep_id int);#插入数据insert into department values(200,'技术'),(201,'人力资源'),(202,'销售'),(203,'运营');insert into employee(name,sex,age,dep_id) values('egon','male',18,200),('alex','female',48,201),('wupeiqi','male',38,201),('yuanhao','female',28,202),('liwenzhou','male',18,200),('jingliyang','female',18,204);#查看表结构和数据mysql> desc department;+-------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+-------------+------+-----+---------+-------+| id | int(11) | YES | | NULL | || name | varchar(20) | YES | | NULL | |+-------+-------------+------+-----+---------+-------+mysql> desc employee;+--------+-----------------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+--------+-----------------------+------+-----+---------+----------------+| id | int(11) | NO | PRI | NULL | auto_increment || name | varchar(20) | YES | | NULL | || sex | enum('male','female') | NO | | male | || age | int(11) | YES | | NULL | || dep_id | int(11) | YES | | NULL | |+--------+-----------------------+------+-----+---------+----------------+mysql> select * from department;+------+--------------+| id | name |+------+--------------+| 200 | 技术 || 201 | 人力资源 || 202 | 销售 || 203 | 运营 |+------+--------------+mysql> select * from employee;+----+------------+--------+------+--------+| id | name | sex | age | dep_id |+----+------------+--------+------+--------+| 1 | egon | male | 18 | 200 || 2 | alex | female | 48 | 201 || 3 | wupeiqi | male | 38 | 201 || 4 | yuanhao | female | 28 | 202 || 5 | liwenzhou | male | 18 | 200 || 6 | jingliyang | female | 18 | 204 |+----+------------+--------+------+--------+表department与employee自https://www.cnblogs.com/Eva-J/articles/9688383.html

2.建立连接

2.1. 交叉连接:生成笛卡儿积

  笛卡儿积(cartesian product)由没有连接条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

范例:

mysql> select * from employee,department;+----+------------+--------+------+--------+------+--------------+| id | name       | sex    | age  | dep_id | id   | name         |+----+------------+--------+------+--------+------+--------------+|  1 | egon       | male   |   18 |    200 |  200 | 技术         ||  1 | egon       | male   |   18 |    200 |  201 | 人力资源     ||  1 | egon       | male   |   18 |    200 |  202 | 销售         ||  1 | egon       | male   |   18 |    200 |  203 | 运营         ||  2 | alex       | female |   48 |    201 |  200 | 技术         ||  2 | alex       | female |   48 |    201 |  201 | 人力资源     ||  2 | alex       | female |   48 |    201 |  202 | 销售         ||  2 | alex       | female |   48 |    201 |  203 | 运营         ||  3 | wupeiqi    | male   |   38 |    201 |  200 | 技术         ||  3 | wupeiqi    | male   |   38 |    201 |  201 | 人力资源     ||  3 | wupeiqi    | male   |   38 |    201 |  202 | 销售         ||  3 | wupeiqi    | male   |   38 |    201 |  203 | 运营         ||  4 | yuanhao    | female |   28 |    202 |  200 | 技术         ||  4 | yuanhao    | female |   28 |    202 |  201 | 人力资源     ||  4 | yuanhao    | female |   28 |    202 |  202 | 销售         ||  4 | yuanhao    | female |   28 |    202 |  203 | 运营         ||  5 | liwenzhou  | male   |   18 |    200 |  200 | 技术         ||  5 | liwenzhou  | male   |   18 |    200 |  201 | 人力资源     ||  5 | liwenzhou  | male   |   18 |    200 |  202 | 销售         ||  5 | liwenzhou  | male   |   18 |    200 |  203 | 运营         ||  6 | jingliyang | female |   18 |    204 |  200 | 技术         ||  6 | jingliyang | female |   18 |    204 |  201 | 人力资源     ||  6 | jingliyang | female |   18 |    204 |  202 | 销售         ||  6 | jingliyang | female |   18 |    204 |  203 | 运营         |+----+------------+--------+------+--------+------+--------------+24 rows in set (0.01 sec) 

2.2. 内部连接:只连接匹配的行

建立的连接基于两个表之间的相等测试,称之为等值连接(equijoin),也称之为内部连接。

语法

SELECT 表名1.字段名1, 表名1.字段名2, 表名1.字段名3, 表名2.字段名1 FROM 表名1 INNER JOIN 表名2 ON  表名1.字段=表名2.字段;

这里两个表之间的关系是FROM子句的组成部分,以INNER JOIN指定。在使用这种语法时,连接条件用特定的ON子句而不是WHERE子句给出。传递给ON的实际条件与传递给WHERE的相同。

范例

# 找出两张表共有的字段,利用条件从笛卡儿积结果中筛选除了正确的结果。 mysql> select employee.id,employee.name,employee.age,employee.sex,department.name dep_name from employee inner join department on employee.dep_id=department.id;+----+-----------+------+--------+--------------+| id | name      | age  | sex    | dep_name     |+----+-----------+------+--------+--------------+|  1 | egon      |   18 | male   | 技术         ||  2 | alex      |   48 | female | 人力资源     ||  3 | wupeiqi   |   38 | male   | 人力资源     ||  4 | yuanhao   |   28 | female | 销售         ||  5 | liwenzhou |   18 | male   | 技术         |+----+-----------+------+--------+--------------+5 rows in set (0.00 sec)mysql> select employee.id,employee.name,employee.age,employee.sex,department.name dep_name from employee, department where employee.dep_id=department.id;+----+-----------+------+--------+--------------+| id | name      | age  | sex    | dep_name     |+----+-----------+------+--------+--------------+|  1 | egon      |   18 | male   | 技术         ||  2 | alex      |   48 | female | 人力资源     ||  3 | wupeiqi   |   38 | male   | 人力资源     ||  4 | yuanhao   |   28 | female | 销售         ||  5 | liwenzhou |   18 | male   | 技术         |+----+-----------+------+--------+--------------+5 rows in set (0.00 sec)

2.3 外部连接

连接中包含了在相关表中没有关联行的行

外部连接的类型

  存在两种基本的外部连接形式:左外部连接和右外部连接。他们之间的唯一差别时所关联的表的顺序不同。换句话说,左外部连接可通过颠倒FROM或WHERE子句中表的顺序转换为右外部连接。因此,两种类型的外部连接可互换使用,而究竟使用哪一种纯粹是根据方便而定。

2.3.1. 外部连接之左连接

以左表为准,优先显示左表全部记录

语法

SELECT 表名1.字段名1, 表名1.字段名2, 表名1.字段名3, 表名2.字段名1 FROM 表名1 LEFT JOIN 表名2 ON  表名1.字段=表名2.字段;

范例

mysql> select * from employee;+----+------------+--------+------+--------+| id | name       | sex    | age  | dep_id |+----+------------+--------+------+--------+|  1 | egon       | male   |   18 |    200 ||  2 | alex       | female |   48 |    201 ||  3 | wupeiqi    | male   |   38 |    201 ||  4 | yuanhao    | female |   28 |    202 ||  5 | liwenzhou  | male   |   18 |    200 ||  6 | jingliyang | female |   18 |    204 |+----+------------+--------+------+--------+6 rows in set (0.00 sec)mysql> select * from department;+------+--------------+| id   | name         |+------+--------------+|  200 | 技术         ||  201 | 人力资源     ||  202 | 销售         ||  203 | 运营         |+------+--------------+4 rows in set (0.00 sec)mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id;+----+------------+--------------+| id | name       | depart_name  |+----+------------+--------------+|  1 | egon       | 技术         ||  5 | liwenzhou  | 技术         ||  2 | alex       | 人力资源     ||  3 | wupeiqi    | 人力资源     ||  4 | yuanhao    | 销售         ||  6 | jingliyang | NULL         |+----+------------+--------------+6 rows in set (0.00 sec)

2.3.2. 外部连接之右连接

以右表为基准,优先显示右表全部记录

语法

SELECT 表名1.字段名1, 表名1.字段名2, 表名1.字段名3, 表名2.字段名1 FROM 表名1 RIGHT JOIN 表名2 ON  表名1.字段=表名2.字段;

范例

mysql> select * from employee;+----+------------+--------+------+--------+| id | name       | sex    | age  | dep_id |+----+------------+--------+------+--------+|  1 | egon       | male   |   18 |    200 ||  2 | alex       | female |   48 |    201 ||  3 | wupeiqi    | male   |   38 |    201 ||  4 | yuanhao    | female |   28 |    202 ||  5 | liwenzhou  | male   |   18 |    200 ||  6 | jingliyang | female |   18 |    204 |+----+------------+--------+------+--------+6 rows in set (0.00 sec)mysql> select * from department;+------+--------------+| id   | name         |+------+--------------+|  200 | 技术         ||  201 | 人力资源     ||  202 | 销售         ||  203 | 运营         |+------+--------------+4 rows in set (0.00 sec)mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id;+------+-----------+--------------+| id   | name      | depart_name  |+------+-----------+--------------+|    1 | egon      | 技术         ||    2 | alex      | 人力资源     ||    3 | wupeiqi   | 人力资源     ||    4 | yuanhao   | 销售         ||    5 | liwenzhou | 技术         || NULL | NULL      | 运营         |+------+-----------+--------------+6 rows in set (0.00 sec)

2.3.3. 外部连接

显示左右两个表的全部记录,及左连接和右连接的合集

语法

SELECT * FROM 表名1 LEFT JOIN 表名2 ON 表名1.字段1=表名2.字段2 UNION SELECT * FROM 表名1 RIGHT JOIN 表名2 ON 表名1.字段1=表名2.字段2 ;

范例

mysql> select * from employee left join department on employee.dep_id=department.id union select * from employee right join department on employee.dep_id=department.id;+------+------------+--------+------+--------+------+--------------+| id   | name       | sex    | age  | dep_id | id   | name         |+------+------------+--------+------+--------+------+--------------+|    1 | egon       | male   |   18 |    200 |  200 | 技术         ||    5 | liwenzhou  | male   |   18 |    200 |  200 | 技术         ||    2 | alex       | female |   48 |    201 |  201 | 人力资源     ||    3 | wupeiqi    | male   |   38 |    201 |  201 | 人力资源     ||    4 | yuanhao    | female |   28 |    202 |  202 | 销售         ||    6 | jingliyang | female |   18 |    204 | NULL | NULL         || NULL | NULL       | NULL   | NULL |   NULL |  203 | 运营         |+------+------------+--------+------+--------+------+--------------+7 rows in set (0.01 sec)

2.4. 连接查询

如果过滤条件的字段在两个表中都存在,需要加上表名

语法

SELECT 表名1.字段名1, 表名1.字段名2, 表名1.字段名3, 表名2.字段名1 FROM 表名1 INNER JOIN 表名2 ON 表名1.字段=表名2.字段 WHERE 过滤条件...;

SELECT 表名1.字段名1, 表名1.字段名2, 表名1.字段名3, 表名2.字段名1 FROM 表名1 LEFT JOIN 表名2 ON 表名1.字段=表名2.字段 WHERE 过滤条件...;

SELECT 表名1.字段名1, 表名1.字段名2, 表名1.字段名3, 表名2.字段名1 FROM 表名1 RIGHT JOIN 表名2 ON 表名1.字段=表名2.字段 WHERE 过滤条件...;

SELECT * FROM 表名1 LEFT JOIN 表名2 ON 表名1.字段1=表名2.字段2 UNION SELECT * FROM 表名1 RIGHT JOIN 表名2 ON 表名1.字段1=表名2.字段2 WHERE 过滤条件...;

范例

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'wher' at line 1mysql> select employee.id,employee.name,department.name as depart_name from employee inner join department on employee.dep_id=department.id where name regexp 'li';ERROR 1052 (23000): Column 'name' in where clause is ambiguousmysql> select employee.id,employee.name,department.name as depart_name from employee inner join department on employee.dep_id=department.id where employee.name regexp 'li';+----+-----------+-------------+| id | name      | depart_name |+----+-----------+-------------+|  5 | liwenzhou | 技术        |+----+-----------+-------------+1 row in set (0.00 sec)

3.子查询

查询(query)任何SQL语句都是查询。但此术语一般指SELECT语句。

子查询(subquery)即嵌套在其他查询中的查询

特点

  1- 子查询是将一个查询语句嵌套在另一个查询语句中。

  2- 内层查询语句的查询结果,可以为外层查询语句提供查询条件。

  3- 子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字

  4- 还可以包含比较运算符:= 、 !=、> 、<等

3.1 带关键字IN的子句

语法

SELECT 字段 FROM 表名1 WHERE 字段1 IN (SELECT 字段2 FROM 表名2);

范例

mysql> select * from employee;+----+------------+--------+------+--------+| id | name       | sex    | age  | dep_id |+----+------------+--------+------+--------+|  1 | egon       | male   |   18 |    200 ||  2 | alex       | female |   48 |    201 ||  3 | wupeiqi    | male   |   38 |    201 ||  4 | yuanhao    | female |   28 |    202 ||  5 | liwenzhou  | male   |   18 |    200 ||  6 | jingliyang | female |   18 |    204 |+----+------------+--------+------+--------+6 rows in set (0.00 sec)mysql> select * from department;+------+--------------+| id   | name         |+------+--------------+|  200 | 技术         ||  201 | 人力资源     ||  202 | 销售         ||  203 | 运营         |+------+--------------+4 rows in set (0.00 sec)mysql> select id from department;+------+| id   |+------+|  200 ||  201 ||  202 ||  203 |+------+4 rows in set (0.00 sec)mysql> select * from employee where dep_id in (select id from department);+----+-----------+--------+------+--------+| id | name      | sex    | age  | dep_id |+----+-----------+--------+------+--------+|  1 | egon      | male   |   18 |    200 ||  2 | alex      | female |   48 |    201 ||  3 | wupeiqi   | male   |   38 |    201 ||  4 | yuanhao   | female |   28 |    202 ||  5 | liwenzhou | male   |   18 |    200 |+----+-----------+--------+------+--------+5 rows in set (0.00 sec) 

3.2 带运算符的子查询

语法

SELECT 字段 FROM 表名1 WHERE 字段1 比较运算符 (SELECT 字段2 FROM 表名2);

范例

mysql> select name,age from employee where age > (select avg(age) from employee);+---------+------+| name    | age  |+---------+------+| alex    |   48 || wupeiqi |   38 |+---------+------+2 rows in set (0.00 sec)

3.3 带EXISTS关键字的子查询

当子查询语句为真的时候,执行外层查询语句。反之,则不进行外部查询语句。

语法

SELECT 字段 FROM 表名1 EXISTS (子查询语句);

范例

# 子查询语句为假,不执行外层查询语句 mysql> select * from employee where exists (select id from department where id=205);Empty set (0.00 sec) # 子查询语句为真,执行外层查询语句mysql> select * from employee where exists (select id from department where id=201);+----+------------+--------+------+--------+| id | name       | sex    | age  | dep_id |+----+------------+--------+------+--------+|  1 | egon       | male   |   18 |    200 ||  2 | alex       | female |   48 |    201 ||  3 | wupeiqi    | male   |   38 |    201 ||  4 | yuanhao    | female |   28 |    202 ||  5 | liwenzhou  | male   |   18 |    200 ||  6 | jingliyang | female |   18 |    204 |+----+------------+--------+------+--------+6 rows in set (0.00 sec)

 

转载于:https://www.cnblogs.com/gongniue/p/10561451.html

你可能感兴趣的文章
安装ntop
查看>>
ssh远程登录讲解
查看>>
mysql的备份脚本
查看>>
linux下mysql的root密码忘记解决方法
查看>>
7.索引的性能分析
查看>>
在 Delphi 下使用 DirectSound (17): 频率均衡效果器 IDirectSoundFXParamEq8
查看>>
文件操作命令一cp 2
查看>>
Multi-Mechanize工程目录结构说明
查看>>
halt
查看>>
标准ACL+扩展ACL+命名ACL
查看>>
Meteor应用的启动过程分析
查看>>
九曲黄河万里沙,浪淘风簸自天涯 — 正则表达式
查看>>
欲哭无泪,联想笔记本性价比
查看>>
很简单的在Ubuntu系统下安装字体和切换默认字体的方法
查看>>
我的友情链接
查看>>
dojo框架用hitch实现函数与上下文的绑定
查看>>
ubuntu编译安装vim7.4
查看>>
python之利用PIL库实现页面的图片验证码及缩略图
查看>>
IP-COM设置×××
查看>>
VPC配置案例
查看>>