联结是一种机制,用来在一条 SELECT 语句中关联表。使用特殊的语句,可以联结多个表,同时只返回一组输出。
在存储数据时,一般会将数据存储在多个表中,这样更利于处理。但一个 SELECT 语句并没有办法从多张表中检索数据。而使用联结可以解决该问题。
因为联结涉及到多个表,所以相同的列名必须使用完全限定列名。完全限定列名指的是:用一个点号分隔表名与列名。
表别名
联结一般会涉及多张表,对不同的表取不同的别名,不但清晰方便,而且是自联结必须的。
可以通过关键字 AS 为表指定不同的别名。在使用条件时,可以直接使用表别名代替原表名。
WHERE 联结
使用 WHERE 创建联结非常简单,只需要指定要查询的表以及表之间的关系条件即可。
SELECT BillingAddress,invoices.[CustomerId],customers.[FirstName],customers.[SupportRepId],employees.[Email] -- 指定从三个表中查询的数据
FROM invoices,customers,employees -- 指定要查询的三个表
WHERE invoices.[CustomerId]=customers.[CustomerId] AND customers.[SupportRepId]=employees.[EmployeeId]; -- 为三个表建立联结条件
上述语句会从三个表中查询需要的数据。
通过 WHERE 语句,将三个表中的数据进行关联。
对于上面语句可以这么理解得到的结果:首先生成迪卡尔积,并且列名都是完全限定列名(表名.列名),然后将不满足 WHERE 条件的行剔除,剩余的就是上述条件返回的。
联结多个表时,与上述语法一样。
INNER JOIN
上面通过 WHERE 语句写的联结就是内联结,但 WHERE 是内联结的简写形式。对于内联结,也可通过 INNER JOIN 与 ON。
SELECT BillingAddress,invoices.[CustomerId],customers.[FirstName],customers.[SupportRepId],employees.[Email] -- 指定从三个表中查询的数据
FROM customers INNER JOIN invoices INNER JOIN employees -- 指定要查询的三个表
ON invoices.[CustomerId]=customers.[CustomerId] AND customers.[SupportRepId]=employees.[EmployeeId] LIMIT 1 OFFSET 0; -- 为三个表建立联结条件
与 WHERE 有以下几点区别:
FROM 语句后,各表之间通过 INNER JOIN 连接。
将 WHERE 关键字替换成 ON,但具体的写法不变。
自联结
自己联结自己就是自联结
本例中所用的表的创建语句如下:
CREATE TABLE IF NOT EXISTS "em" (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" text,
"schoolId" integer
);
查询语句如下:
SELECT m.name,m.schoolId FROM em AS e,em AS m
WHERE e.name="lisi" AND e.schoolId = m.schoolId;
本 sql 会查出所有与 lisi 的 schoolId 相同的行。
自联结需要指定表别名。
SELECT 语句中一定要分清楚是哪个表中的哪列。如果将上面的 m.name 写成 e.name,那么得到的所有 name 都将是 lisi。
可以理解为首先生成笛卡尔积,列名是全列名 ( 通过表别名进行区分 ),然后对笛卡尔积表进行过滤。因此,如果 SELECT 语句中指定错了别名,得到的结果将完全不同。
自然联结
在联结中,至少有一列不止出现在一个表中 ( 使用该列对表进行关系 ) ,当返回所有数据时,相同的列会出现多次。
自然联结会排除多次出现的列,相同的列只会出现一次。
自然联结并没有什么特殊的语法,需要程序自己指定 —— 人为的将重复的列返回一次。
一般来说第一个表返回所有,其余的表就明确列出要返回的列。
SELECT a.*,ar.[Name] FROM albums AS a,artists AS ar
WHERE a.[ArtistId]=ar.[ArtistId] LIMIT 1 OFFSET 0;
而 a 与 ar 表中相同的列是 ArtistId。
a.* 是返回 a 表中所有的列,而 ar.[Name] 表示返回 ar 表中的 Name 列。想检索别的列,则依次指定即可,只保证指定的列没有重复的,就是自然联结。
外联结
与内联结相对:内联结将所有的不满足条件行剔除,而外联结会保留其中的一部分。
外联结分为左外联结与右外联结。
所有的外联结必须与 ON 结合使用。
左外联结,如果 A 左外联结 B,则将 A 的所有记录都保留,而 B 中只保留满足联结条件的记录。关键字为 LEFT OUTER JOIN。
右外联结:与左外联结相反,A 右外联结 B,则将 B 中的所有记录保留,而 A 中只保留满足联结条件的。关键字为 RIGHT OUTER JOIN。sqlite不支持右外联结。
假如 A 左外联结 B,A 中所有行都会被检索出来。它对应的 B 中的行的数据全部为 null。
外联结分为左外联结与右外联结,但调整表的顺序,可以将左外联结转换为右外联结,反之也行。
SELECT Customers.[cust_id],Orders.[order_num]
FROM Customers LEFT OUTER JOIN Orders
ON Customers.[cust_id] = Orders.[cust_id]
从结果中可以看了,对于 cust_id 为 2 的行来说,虽然在 Orders 表中没有对应的记录,但它一样被检索出来,只不过对应的 Orders 中的列值都为 null。