盘点一下Mysql中的一些小知识(四)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 盘点一下Mysql中的一些小知识(四)

联结表

联结表的目的是为了用一条select语句检索多张表的数据。

联结的关键在于主键外键。主键唯一标识一行数据,外键则是另一张表的主键。(包含外键的表称为从表)

products表只存储产品信息,它除了存储供应商ID(vendors表的主键)外不存储其他供应商信息。vendors表的主键又叫作products的外键,它将vendors表与products表关联。(products是从表,包含外键;vendors是主表)

mysql> select vend_name,prod_name,prod_price
    -> from vendors,products
    ->  where vendors.vend_id = products.vend_id
    -> order by vend_name,prod_name;
+-------------+----------------+------------+
| vend_name   | prod_name      | prod_price |
+-------------+----------------+------------+
| ACME        | Bird seed      |      10.00 |
| ACME        | Carrots        |       2.50 |
| ACME        | Detonator      |      13.00 |
| ACME        | Safe           |      50.00 |
| ACME        | Sling          |       4.49 |
| ACME        | TNT (1 stick)  |       2.50 |
| ACME        | TNT (5 sticks) |      10.00 |
| Anvils R Us | .5 ton anvil   |       5.99 |
| Anvils R Us | 1 ton anvil    |       9.99 |
| Anvils R Us | 2 ton anvil    |      14.99 |
| Jet Set     | JetPack 1000   |      35.00 |
| Jet Set     | JetPack 2000   |      55.00 |
| LT Supplies | Fuses          |       3.42 |
| LT Supplies | Oil can        |       8.99 |
+-------------+----------------+------------+
14 rows in set (0.01 sec)

两张表:vendors,products

不同的列:**vend_name **和 prod_name,prod_price

完全限定列名:vendors.vend_id = products.vend_id 区分两张表的相同字段vend_id

where条件过滤

WHERE子句作为过滤条件,它只包含那些匹配给定条件(这里是联结条件)的行。没有WHERE子句,第一个表中的每个行将与第二个表中的每个行配对,而不管它们逻辑上是否可以配在一起。不使用where条件过滤最终结果会采用笛卡尔积,其数据并不是我们想要的结果。

笛卡尔积

集合的乘积

image.png

对于最终的结果应该是3*3 =9 种组合

mysql> select count(*) from vendors,products;
+----------+
| count(*) |
+----------+
|       84 |
+----------+
1 row in set (0.00 sec)
mysql> select count(*) from vendors;
+----------+
| count(*) |
+----------+
|        6 |
+----------+
1 row in set (0.00 sec)
mysql> select count(*) from products;
+----------+
| count(*) |
+----------+
|       14 |
+----------+
1 row in set (0.00 sec)

结果计算:84=6*14

内连接

目前为止所用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内部联结。

不同写法,一样的效果:

mysql> select vend_name,prod_name,prod_price from vendors inner join products on vendors.vend_id = products.vend_id;
+-------------+----------------+------------+
| vend_name   | prod_name      | prod_price |
+-------------+----------------+------------+
| Anvils R Us | .5 ton anvil   |       5.99 |
| Anvils R Us | 1 ton anvil    |       9.99 |
| Anvils R Us | 2 ton anvil    |      14.99 |
| LT Supplies | Fuses          |       3.42 |
| LT Supplies | Oil can        |       8.99 |
| ACME        | Detonator      |      13.00 |
| ACME        | Bird seed      |      10.00 |
| ACME        | Carrots        |       2.50 |
| ACME        | Safe           |      50.00 |
| ACME        | Sling          |       4.49 |
| ACME        | TNT (1 stick)  |       2.50 |
| ACME        | TNT (5 sticks) |      10.00 |
| Jet Set     | JetPack 1000   |      35.00 |
| Jet Set     | JetPack 2000   |      55.00 |
+-------------+----------------+------------+
14 rows in set (0.00 sec)
mysql> select vend_name,prod_name,prod_price from vendors , products where vendors.vend_id = products.vend_id;
+-------------+----------------+------------+
| vend_name   | prod_name      | prod_price |
+-------------+----------------+------------+
| Anvils R Us | .5 ton anvil   |       5.99 |
| Anvils R Us | 1 ton anvil    |       9.99 |
| Anvils R Us | 2 ton anvil    |      14.99 |
| LT Supplies | Fuses          |       3.42 |
| LT Supplies | Oil can        |       8.99 |
| ACME        | Detonator      |      13.00 |
| ACME        | Bird seed      |      10.00 |
| ACME        | Carrots        |       2.50 |
| ACME        | Safe           |      50.00 |
| ACME        | Sling          |       4.49 |
| ACME        | TNT (1 stick)  |       2.50 |
| ACME        | TNT (5 sticks) |      10.00 |
| Jet Set     | JetPack 1000   |      35.00 |
| Jet Set     | JetPack 2000   |      55.00 |
+-------------+----------------+------------+
14 rows in set (0.00 sec)
mysql>

等值连接:2个表会先进行笛卡尔乘积运算,生成一个新表格,占据在电脑内存里,当表的数据量很大时,很耗内存,这种方法效率比较低,尽量不用。

内连接:2个表根据共同ID进行逐条匹配,不会出现笛卡尔乘积的现象,效率比较高,优先使用这种方法。

多表联结

SQL对一条SELECT语句中可以联结的表的数目没有限制。所以,继续往后加就行。🍁

mysql> select prod_name,vend_name,prod_price,quantity
    -> from orderitems,products,vendors
    -> where products.vend_id = vendors.vend_id
    -> and orderitems.prod_id = products.prod_id
    -> and order_num=20005;
+----------------+-------------+------------+----------+
| prod_name      | vend_name   | prod_price | quantity |
+----------------+-------------+------------+----------+
| .5 ton anvil   | Anvils R Us |       5.99 |       10 |
| 1 ton anvil    | Anvils R Us |       9.99 |        3 |
| TNT (5 sticks) | ACME        |      10.00 |        5 |
| Bird seed      | ACME        |      10.00 |        1 |
+----------------+-------------+------------+----------+
4 rows in set (0.01 sec)

子查询例子:

假如需要列出订购物品TNT2的所有客户:

  • 检索包含物品TNT2的所有订单的编号。
    select order_num from orderitems where prod_id = 'tnt2'
  • 检索具有前一步骤列出的订单编号的所有客户的ID。
    select cust_id from orders where order_num in 。。。
  • 检索前一步骤返回的所有客户ID的客户信息。
    select cust_name ,cust_contact from customers where cust_id in。。。。。
mysql> select cust_name ,cust_contact from customers where cust_id in 
  (select cust_id from orders where order_num in 
      (select order_num from orderitems where prod_id = 'tnt2'));
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+
2 rows in set (0.01 sec)

改写:

mysql> select cust_name,cust_contact
    -> from customers,orders,orderitems
    -> where customers.cust_id = orders.cust_id
    -> and orderitems.order_num = orders.order_num
    -> and prod_id = 'tnt2';
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+
2 rows in set (0.00 sec)

似乎多表联结更加无脑

找出相关表,无脑跟在from后面,无脑联结

where后面跟上联结条件(匹配相关外键与主键)以及过滤条件

高级联结

别名使用

mysql> select cust_name,cust_contact
    -> from customers as cus ,orders as o,orderitems as oi
    -> where cus.cust_id = o.cust_id
    -> and oi.order_num = o.order_num
    -> and prod_id = 'tnt2';
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+
2 rows in set (0.00 sec)
# 当然,as可省略
mysql> select cust_name,cust_contact
    -> from customers  cus ,orders  o,orderitems  oi
    -> where cus.cust_id = o.cust_id
    -> and oi.order_num = o.order_num
    -> and prod_id = 'tnt2';
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+
2 rows in set (0.00 sec)

📣表别名只在查询执行中使用。与列别名不一样,表别名不返回到客户机。

自联结

也就是自己和自己做关联

假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。

等值连接:

  • 联结两张products表,起名为p1 p2
  • 组合过滤条件,p2.vend_id = p1.vend_id联结两张表,p2.prod_id = 'dtntr'过滤数据
mysql> select p1.prod_id ,p1.prod_name
    -> from products p1,products p2
    -> where p2.prod_id = 'dtntr'
    -> and p2.vend_id = p1.vend_id;
+---------+----------------+
| prod_id | prod_name      |
+---------+----------------+
| DTNTR   | Detonator      |
| FB      | Bird seed      |
| FC      | Carrots        |
| SAFE    | Safe           |
| SLING   | Sling          |
| TNT1    | TNT (1 stick)  |
| TNT2    | TNT (5 sticks) |
+---------+----------------+
7 rows in set (0.00 sec)

子查询:

  • 查询id为DTNTR物品的供应商的vend_id
    select vend_id from products where prod_id ='dtntr'
  • 检索该供应商的所有物品
    select prod_id,prod_name from products where vend_id =
mysql> select prod_id,prod_name
    -> from products
    -> where vend_id =(select vend_id
    -> from products
    -> where prod_id ='dtntr');
+---------+----------------+
| prod_id | prod_name      |
+---------+----------------+
| DTNTR   | Detonator      |
| FB      | Bird seed      |
| FC      | Carrots        |
| SAFE    | Safe           |
| SLING   | Sling          |
| TNT1    | TNT (1 stick)  |
| TNT2    | TNT (5 sticks) |
+---------+----------------+
7 rows in set (0.01 sec)

自然联结

自然连接在等值连接中去除重复的属性列。(无重复列)

迄今为止我们建立的每个内部联结都是自然联结,很可能我们永远都不会用到不是自然联结的内部联结。

外部联结

许多联结将一个表中的行与另一个表中的行相关联。但有时候会需要包含没有关联行的那些行。

内部联结展示已关联的元组,外部联结可展示没有关联的元组。

检索所有客户及其订单:

mysql> select cus.cust_id ,o.order_num from customers cus inner join orders
o on cus.cust_id = o.cust_id;
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
|   10001 |     20005 |
|   10001 |     20009 |
|   10001 |     20010 |
|   10003 |     20006 |
|   10004 |     20007 |
|   10005 |     20008 |
+---------+-----------+
6 rows in set (0.00 sec)

检索所有客户,包括那些没有订单的客户:

mysql> select cus.cust_id ,o.order_num from customers cus left join orders o on cus.cust_id = o.cust_id;
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
|   10001 |     20005 |
|   10001 |     20009 |
|   10001 |     20010 |
|   10002 |      NULL |
|   10003 |     20006 |
|   10004 |     20007 |
|   10005 |     20008 |
+---------+-----------+
7 rows in set (0.00 sec)
mysql>

外部联结分为左外联结left (outer) join和右外联结right (outer) join

它们之间的唯一差别是所关联的表的顺序不同。换句话说,左外部联结可通过颠倒FROM或WHERE子句中表的顺序转换为右外部联结。

mysql> select cus.cust_id ,o.order_num from orders o right outer join customers cus on cus.cust_id = o.cust_id;
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
|   10001 |     20005 |
|   10001 |     20009 |
|   10001 |     20010 |
|   10002 |      NULL |
|   10003 |     20006 |
|   10004 |     20007 |
|   10005 |     20008 |
+---------+-----------+
7 rows in set (0.00 sec)

聚集函数

聚集函数也可以方便地与其他联结一起使用

mysql> select cus.cust_name,cus.cust_id,count(o.order_num) num_ord
    -> from customers cus left join orders o
    -> on cus.cust_id = o.cust_id
    -> group by cus.cust_id;
+----------------+---------+---------+
| cust_name      | cust_id | num_ord |
+----------------+---------+---------+
| Coyote Inc.    |   10001 |       3 |
| Mouse House    |   10002 |       0 |
| Wascals        |   10003 |       1 |
| Yosemite Place |   10004 |       1 |
| E Fudd         |   10005 |       1 |
+----------------+---------+---------+
5 rows in set (0.00 sec)

组合查询

MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个查询结果集返回。

  • 在单个查询中从不同的表返回类似结构的数据;
  • 对单个表执行多个查询,按单个查询返回数据。

组合查询和多个WHERE条件

任何具有多个WHERE子句的SELECT语句都可以作为一个组合查询给出。

union

UNION的使用很简单。所需做的只是给出每条SELECT语句,在各条语句之间放上关键字UNION。

假如需要价格小于等于5的所有物品的一个列表,而且还想包括供应商1001和1002生产的所有物品(不考虑价格)。

不使用union:

mysql> select vend_id,prod_id ,prod_price
    -> from products
    -> where prod_price <=5
    -> or vend_id in (1001,1002);
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
|    1001 | ANV01   |       5.99 |
|    1001 | ANV02   |       9.99 |
|    1001 | ANV03   |      14.99 |
|    1003 | FC      |       2.50 |
|    1002 | FU1     |       3.42 |
|    1002 | OL1     |       8.99 |
|    1003 | SLING   |       4.49 |
|    1003 | TNT1    |       2.50 |
+---------+---------+------------+
8 rows in set (0.00 sec)

使用union:

mysql> select vend_id ,prod_id,prod_price
    -> from products
    -> where prod_price <=5
    -> union
    -> select vend_id ,prod_id ,prod_price
    -> from products
    -> where vend_id in(1001,1002);
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
|    1003 | FC      |       2.50 |
|    1002 | FU1     |       3.42 |
|    1003 | SLING   |       4.49 |
|    1003 | TNT1    |       2.50 |
|    1001 | ANV01   |       5.99 |
|    1001 | ANV02   |       9.99 |
|    1001 | ANV03   |      14.99 |
|    1002 | OL1     |       8.99 |
+---------+---------+------------+
8 rows in set (0.00 sec)

在这个简单的例子中,使用UNION可能比使用WHERE子句更为复杂。但对于更复杂的过滤条件,或者从多个表(而不是单个表)中检索数据的情形,使用UNION可能会使处理更简单。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
关系型数据库 MySQL
|
2月前
|
Oracle 关系型数据库 MySQL
MySQL
是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL是最
|
存储 SQL Oracle
|
SQL 算法 关系型数据库
【MySQL】 MRR
【MySQL】 MRR
127 0
|
SQL 关系型数据库 MySQL
|
JSON 算法 关系型数据库
MySQL 8.0.32如期而至
MySQL 8.0版本计划 MySQL 8.0开始采用快速迭代开发模式,基本上是每隔3个月就发布一个新的小版本。去年1月18日(2022.1.18)发布MySQL 8.0.28,今年1月17日发布MySQL 8.0.32,再看看其他几个版本的时间,还真是贼守时啊。
355 0
|
存储 关系型数据库 MySQL
【MySQL】MySQL知识总结
【MySQL】MySQL知识总结
1023 0
【MySQL】MySQL知识总结
|
关系型数据库 MySQL
MySQL练习13——where in和not in
MySQL练习13——where in和not in!
|
SQL 关系型数据库 MySQL
MySQL(六)
MySQL(六),一起来学习吧。
|
SQL JSON Oracle
MySQL 8.0来了,逆之者亡...
MySQL 8.0来了,逆之者亡...
197 0
MySQL 8.0来了,逆之者亡...