任务四
MySQL 基础 (三)- 表联结
任务时间
请于3月2日22:00前完成,在本文章评论打卡。逾期尚未打卡的会被清退。
学习内容
MySQL别名
INNER JOIN
LEFT JOIN
CROSS JOIN
自连接
UNION
以上几种方式的区别和联系
作业
项目五:组合两张表 (难度:简单)
在数据库中创建表1和表2,并各插入三行数据(自己造)
表1: Person
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
+-------------+---------+
PersonId 是上表主键
表2: Address
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
+-------------+---------+
AddressId 是上表主键
编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:FirstName, LastName, City, State
项目六:删除重复的邮箱(难度:简单)
编写一个 SQL 查询,来删除 email 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。
+----+---------+
| Id | Email |
+----+---------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
+----+---------+
Id 是这个表的主键。
例如,在运行你的查询语句之后,上面的 Email表应返回以下几行:
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | [email protected] |
| 2 | [email protected] |
+----+------------------+
SQL最强大的功能之一就是能在数据查询的执行中联结(join) 表。 联结是利用 SQL的 SELECT能执行的最重要的操作,很好地理解联结及其语法是学习 SQL的极为重要的部分。
联结是一种机制,用来在一条select语句中关联表,因此称之为联结(联结在运行时关联表中正确的行)
关系表:把信息分解成多个表,一类数据一个表,各表通过某些常用值(即关系设计中的关系(relational))互相关联;关系表的设计就是要把信息分解成多个表,一类数据一个表。各表通过某些共同的值互相关联(所以才叫关系数据库)。
外键(foreign key):外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系
联结表的优点:(1)数据信息不重复,从而不浪费时间和空间 (2)如果某个数据信息变动,可以只更新该表中的某个记录,相关表数据不用变更 (3)数据无重复,可以更有效的存储和方便的处理,伸缩性强(能够适应不断增加的工作量而不失败,设计良好的数据库或者应用程序称为可伸缩性好(scale well))。
SELECT vend_name, prod_name, prod_price
FROM Vendors, Products
WHERE Vendors.vend_id = Products.vend_id;
这里最大的差别是所指定的两列(prod_name和 prod_price)在一个表中,而第三列(vend_name)在另一个表中。这条语句的 FROM子句列出了两个表:Vendors和 Products。它们就是这条 SELECT语句联结的两个表的名字。 这两个表用 WHERE子句正确地联结, WHERE子句指示 DBMS将Vendors表中的vend_id与Products表中的vend_id匹配起来。要匹配的两列指定为 Vendors.vend_id和 Products.vend_id,这里需要这种完全限定列名(在引用的列可能出现歧义时,必须使用完全限定列名(用一个句点分隔表名和列名))。
注意:where子句的重要性。
在一条select语句中联结几个表时,相应的关系是在运行中构造的;在联结两个甚至多个表时,实际上是将第一个表中的每一行与第二个表中的每一行配对,where子句作为过滤条件,它只包含匹配的给定条件的行。
没有where子句,第一个表中每个行将与第二个表中的每个行匹配,而不管逻辑上是否可以配在一起。
交叉联结返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。由没有联结条件的表关系返回的结果称为笛卡尔积(检索出的行的数目将是第一个表中的行数乘以第二个表中的行数);
注意: 应保证所有联结都有where子句,否则MySQL将返回比想要的数据多得多的数据,还应保证where子句的正确性。
等值联结(equijoin):基于两个表之间的相等测试,也称为内联结(inner join)。下面的 SELECT语句返回与前面例子完全相同的数据:
SELECT vend_name, prod_name, prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;
此语句中的SELECT与前面的SELECT语句相同,但FROM子句不同。 这里,两个表之间的关系是以INNERJOIN指定的部分FROM子句。在使用这种语法时, 联结条件用特定的 ON子句而不是 WHERE子句给出。 传递给ON的实际条件与传递给WHERE的相同。
SQL对一条select语句中可以联结的表的数目没有限制,创建规则也基本相同(首先列出所有表,然后定义表之间的关系)
注意: MySQL在运行时关联指定的每个表以处理联结,这样很耗费资源,因此使用中应注意,不要联结不必要的表。
别名除了允许用于列名和计算字段外,SQL还允许给表名起别名,好处在于:(1)缩短 SQL语句;(2)允许在一条SELECT语句中多次使用相同的表。
为表取别名语法:SELECT * FROM 表名 [AS] 别名;
为字段取别名:SELECT 字段名 [AS] 别名 [,字段名 [AS] 别名,……] FROM 表名;
注意: 表别名不仅可用于where子句,还可用于select列表,order by子句以及语句其他部分(表别名只在查询执行中使用,表别名不返回到客户端主机)。而且AS关键字在指定别名的时候可以省略不写
自联结:本质是把一张表当成两张表来使用。自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。
select p1.user_id, p1.user_name
from usertable as p1, usertable as p2
where p1.user_id = p2.user_id
and p2.user_id = '10086';
这条SQL语句中,usertable表第一次出现为别名p1,第二次为别名p2,在select语句中明确使用p1前缀给出所需列名,否则MySQL将返回错误,因为其无法正确区分想要的具体为哪一列;
无论何时对表进行联结,应至少有一个列出现在不止一个表中(被联结的列);标准的联结返回所有数据,自然联结排除多次出现,只返回一次。
一般使用select *通配符,对其他表的列使用明确的自己来完成,通配符只对第一个表使用,所有其他列明确列出。
用来联结那些在相关表中没有关联行的行,这种类型的联结称为外联结。
SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
这条SELECT语句使用了关键字OUTERJOIN来指定联结类型(而不是在 WHERE子句中指定)。在使用 OUTER
JOIN语法时,必须使用** RIGHT或 LEFT**关键字指定包括其所有行的表(RIGHT指出的是OUTERJOIN右边的表,而LEFT指出的是OUTERJOIN左边的表)。
这条select语句使用关键字outer join来指定联结的类型(不是在where子句中指定);在使用outer join语法时,必须使用left或right指定包括其他所有行的表(right指出右边的表,left指出左边的表).上面的例子使用 LEFT OUTER JOIN从 FROM子句左边的表(Customers表)中选择所有行。 为了从右边的表中选择所有行,需要使用RIGHT OUTER JOIN。
注意: 总是有两种基本的外联结形式:左外联结和右外联结。它们之间的唯一差别是所关联的表的顺序。
联合连接:这是一种很少见的连接方式。Oracle、MySQL均不支持,其作用是:找出全外连接和内连接之间差异的所有行。这在数据分析中排错中比较常用。也可以利用数据库的集合操作来实现此功能。
select * from t1 join t2;
select * from t1 left join t2 on t1.id = t2.id;
select * from t1 right join t2 on t1.id =t2.id;
select * from t1 inner join t2 on t1.id = t2.id;
SELECT a.ename '备注aname', b.ename '备注bname' FROM emp a LEFT JOIN emp b ON a.leaderid = b.eid;