SQL 使用联结(二)

连载的上一篇文章,我们学习了内联结的创建,包括使用 WHERE 过滤联结、使用更明确的语法 INNER JOIN ... ON 创建内联结。本节内容,我们将进步深入学习联结操作,包含创建和使用表的别名、自联结、外连接(左外连接和右外联结),下面开始我们今天的学习吧~

订单表、顾客表、订单明细表

创建和使用表别名

SQL 除了可以对列名和计算字段使用别名,还允许给表起名字。比如,下面涉及到 3 张表的查询语句中,我们就为每张表都起了一个别名。

SELECT
    C.cust_id,
    C.cust_name,
    C.cust_contact 
FROM
    Customers AS C,
    Orders AS O,
    OrderItems AS OI 
WHERE
    C.cust_id = O.cust_id 
    AND o.order_num = OI.order_num 
    AND OI.prod_id = 'RGAN01';

为表创建别名之后,在使用完全限定列名时就可以直接通过表的别名来引用了。上述 SQL 成功检索出了购买了商品 RGAN01 的顾客姓名和联系人。

注:Oracle 数据库不支持 AS 关键字,创建别名时直接在表名后添加别名即可,如 Customers C 即可为 Customers 表指定别名 C

为表创建别名的好处:

  • 缩短 SQL 语句,书写简洁;
  • 允许在一条 SELECT 语句中多次使用相同的表。

关于第二个好处,什么时候会在一条 SELECT 语句中多次使用一张表呢?听起来怪怪的 (* ̄︶ ̄) 这就需要继续我们的联结话题了,自联结的时候就会在一条 SQL 中多次使用一张表!

创建自联结

我们举个案例来学习自联结。有如下的一张会员信息表:

cust_id 为会员 ID,具有唯一性;cust_name 此处代指会员所在的公司;cust_contact 为雇员姓名。现在,假设我们需要检索出和 Jim Jones 雇员属于同一家公司的所有会员信息。

如果使用子查询的话,我们可以很轻松地编写出如下的 SQL

SELECT
    cust_id, cust_name, cust_contact 
FROM
    Customers 
WHERE
    cust_name IN ( SELECT cust_name FROM Customers WHERE cust_contact = 'Jim Jones' );

首先找到雇员 Jim Jones 所在的公司,然后找到该公司的所有会员信息。其中子查询使用的表名和外部查询使用的是同一张表 Customers

子查询可以转换为内联结的形式:

SELECT
    c1.cust_id,
    c1.cust_name,
    c1.cust_contact 
FROM
    Customers AS c1,
    Customers AS c2 
WHERE
    c1.cust_name = c2.cust_name 
    AND c2.cust_contact = 'Jim Jones';

上述查询中联结的两张表其实是一张表,即 Customers 表:Customers 第一次出现使用了别名 c1,第二次出现使用了别名 c2 ,这样我们就可以在一条 SELECT 语句中多次使用这一张表了,并使用完全限定列名。

当联结的多张表实际上是同一个表的时候,就是自联结。上述 SQL 通过自联结联结两张 Customers 表,然后根据 c1.cust_name = c2.cust_namec2.cust_contact = 'Jim Jones' 过滤联结。检索结果如下:

注:自联结的性能要优于子查询。

创建外联结

前面我们介绍的内联结将一个表中的行与另一个表中的行相关联,但有时候需要包含没有关联行的那些行。比如:

  • 统计每个客户的订单数量,包含未下单的客户;
  • 统计每类产品的订购数量,包含没有被订购的产品;

上述场景,联结包含了那些在相关表中没有 关联行 的记录,这种联结就是外联结了。

举个例子:使用内联结检索所有顾客及其订单:

SELECT
    C.cust_id,
    C.cust_name,
    O.order_num 
FROM
    Customers AS C
    INNER JOIN Orders AS O ON C.cust_id = O.cust_id
ORDER BY 
    C.cust_id;

检索运行结果:

内联结返回的记录中,每个顾客都至少有一个订单号与之对应。那如果我们需要返回全部的顾客,不管顾客有没有下单怎么办呢?

这就需要用到外联结了,外联结有两种基本的形式:左外联结 LEFT JOIN ... ON 和右外联结 RIGHT JOIN ... ON;通过调整 FROMJOIN 子句中表的顺序,两种外联结可以相互转换。

下面,我们使用左外联结改写上述 SQL

SELECT
    C.cust_id,
    C.cust_name,
    O.order_num 
FROM
    Customers AS C
    LEFT JOIN Orders AS O ON C.cust_id = O.cust_id 
ORDER BY
    C.cust_id;

运行结果:

与内联结关联两个表中的行不同的是,外联结还包括没有关联行的记录。上述 SQL 使用 LEFT JOIN ... ONLEFT JOIN 子句左侧的表 Customers 中选择所有行,LEFT JOIN 右侧的表只选择关联行。因此,返回结果中就会出现没有关联订单的顾客记录。

注:SQLite 不支持 RIGHT JOIN ... ON ,小鱼这里就不演示右联结了。

在联结中使用聚合函数

聚合函数用来汇总数据,之前我们介绍聚合函数时,都是在一张表中汇总所有记录,或者分组聚合每组记录。其实,聚合函数也可以与联结一起使用!

我们来看下面的例子,统计所有下单顾客中,每位客户的订单总数:

SELECT
    Customers.cust_id,
    Customers.cust_name,
    COUNT( Orders.order_num ) AS order_num 
FROM
    Customers
    INNER JOIN Orders ON Customers.cust_id = Orders.cust_id 
GROUP BY
    Customers.cust_id 
ORDER BY
    order_num DESC;

上述 SQL 使用 INNER JOIN ... ONCustomers 表和 Orders 表相互关联,GROUP BY 按顾客 ID 分组数据库,COUNT( Orders.order_num ) 对每个客户的订单进行计数,作为 order_num 字段返回。

如果使用外联结,可以包含订单数量为 0 的顾客:

SELECT
    Customers.cust_id,
    Customers.cust_name,
    COUNT( Orders.order_num ) AS order_num 
FROM
    Customers
    LEFT JOIN Orders ON Customers.cust_id = Orders.cust_id 
GROUP BY
    Customers.cust_id 
ORDER BY
    order_num DESC;

检索运行结果:

总结

本节我们学习了如何创建表别名以及创建表别名的好处,此外还学习了外联结的创建以及外联结与内联结的不同。最后,我们讨论了如何与联结一起使用聚合函数。以上就是本节的全部内容啦,学习愉快 (*^▽^*)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容