《SQL必知必会》笔记7-高级联结(as、self-join、outer join)、组合查询union

1 创建高级联结(别名、自联结、外联结)

1.1 使用表别名AS

使用别名的两个主要理由:

  • 缩短SQL语句。
  • 允许在一条SELECT语句中多次使用相同的表。
SELECT cust_name, cust_contact 
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01';

别名不仅能用于WHERE子句,还可以用于SELECT列表、ORDER BY子句以及其他语句部分。


1.2 使用不同类型的联结

除了内联结INNER JOIN之外,还有三种其他联结方式:自联结(self-join)、自然联结(natural join)和外联结(outer join)。


1.2.1 自联结self-join

自联结指的是要检索的两个表实际上是同一个表。

假如要给与Jim Jones同一公司的所有顾客发送一份邮件。

方法一:子查询

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

方法二:自联结查询

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';

一般来说,许多DBMS处理联结远比处理子查询快得多。


1.2.2 自然联结natural join

在对表进行联结时,至少有一列(被联结的列)不止出现在一个表中。标准的内联结返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次。

自然联结要求只能选择那些唯一的列,一般通过对一个表使用通配符(SELECT *),而对其他表的列使用明确的子集来完成。

SELECT C.*, O.order_num, O.order_date,
 OI.prod_id, OI.quantity, OI.item_price 
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01';

在这个例子中,通配符只对第一个表使用。所有其他列明确列出,所以没有重复的列被检索出来。

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


1.2.3 外联结outer join

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

例如:

  • 对每个顾客下的订单进行计数,包括哪些至今尚未下订单的顾客。
  • 列出所有产品以及订购数量,包括没有人订购的产品。
  • 计算平均销售规模,包括哪些至今尚未下订单的顾客。

在上述例子中,联结包含了那些在相关表中没有关联行的行,这种联结称为外联结(outer join)。

内联结检索所有顾客及其订单:

SELECT Customers.cust_id, Orders.order_num
FROM Customers INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

外联结语法类似,检索包括没有订单顾客在内的所有顾客:

SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT指出的是OUTER JOIN左边的表)。

上面的例子使用LEFT OUTER JOIN从FROM子句左边的表(Customers表)中选择所有行。为了从右边的表中选择所有行,需要使用RIGHT OUTER JOIN,如下例所示。

SELECT Customers.cust_id, Orders.order_num
FROM Customers RIGHT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

还存在另一种外联结,就是全外联结(full outer join),它检索两个表中的所有行并关联那些可以关联的行,全外联结包含了两个表中的不关联的行。(Access、MariaDB、MySQL和SQLite不支持FULL OUTER JOIN语法)

SELECT Customers.cust_id, Orders.order_num
FROM Customers FULL OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

1.3 使用带聚集函数的联结

检索所有顾客及每个顾客所下的订单数:

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

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

SELECT Customers.cust_id,
       COUNT(Orders.order_num) AS num_ord
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id;

1.4 使用联结和联结条件

  1. 注意所使用的联结类型。一般我们使用内联结,但使用外联结也有效。
  2. 保证使用正确的联结条件,否则会返回不正确的数据。
  3. 应该总是提供联结条件,否则会得出笛卡尔积。
  4. 在一个联结中可以包含多个表,甚至可以对每个联结采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前分别测试每个联结,这会使故障排除更为简单。

2 组合查询(UNION)

2.1 组合查询

多数SQL查询只包含从一个或多个表中返回数据的单条SELECT语句,但是SQL也允许执行多个查询(多条SELECT语句),并将结果作为一个查询结果集返回。这些组合查询通常称为并(union)或复合查询(compound query)。

使用组合查询的两个主要情况:

  1. 在一个查询中从不同的表返回结构数据。
  2. 对一个表执行多个查询,按一个查询返回数据。

2.2 创建组合查询

可用UNION操作符来组合数条SQL查询,利用UNION,可给出多条SELECT语句,将它们的结果组合成一个结果集。


2.2.1 使用UNION

给出每条SELECT语句,在各条语句之间放上关键字UNION。

例如,需要Illinois、Indiana和Michigan等美国几个州的所有顾客的报表,还想包括不管位于哪个州的所有的Fun4All。当然可以利用WHERE子句来完成此工作,不过这次我们使用UNION。

使用WHERE语句:

SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
OR cust_name = 'Fun4All';

使用UNION语句:

SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

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


2.2.2 UNION规则

  1. UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔。如果组合四条SELECT语句,将要使用三个UNION关键字。
  2. UNION中的每个查询必须包含相同的列、表达式或聚集函数,各个列不需要以相同的次序列出。
  3. 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含转换的类型(例如,不同的数值类型或不同的日期类型)。

2.2.3 包含或取消重复的行

UNION从查询结果集中自动去除了重复的行,它的行为与一条SELECT语句中使用多个WHERE子句条件一样。使用UNION时,重复的行会自动取消。

如果想返回所有的匹配行,可使用UNION ALL而不是UNION。

SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION ALL
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

2.2.4 对组合查询结果排序

在用UNION组合查询时,只能使用一条ORDER BY子句,它必须位于最后一条SELECT语句之后。

对于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一部分的情况,因此不允许使用多条ORDER BY子句。

SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All'
ORDER BY cust_name, cust_contact;

虽然ORDER BY子句似乎只有最后一条SELECT语句的组成部分,但实际上DBMS将用它来排序所有SELECT语句返回的所有结果。


如果您发现文中有不清楚或者有问题的地方,请在下方评论区留言,我会根据您的评论,更新文中相关内容,谢谢!

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

推荐阅读更多精彩内容

  • SQL与MySQL简介 数据库基础 从SQL的角度来看,数据库就是一个以某种有组织的方式存储的数据集合。我们可以采...
    heming阅读 3,062评论 1 8
  • 1.表中的任何列都可以作为主键, 只要它满足以下条件:任意两行都不具有相同的主键值;每一行都必须具有一个主键值( ...
    Cherryjs阅读 646评论 0 0
  • 关系型数据库和SQL SQL语言的三个部分DML:Data Manipulation Language,数据操纵语...
    Awey阅读 1,937评论 0 13
  • 今天参加了一场精英女性盛典,嘉宾们分享着自己的故事,坚持着自己的初心,每一位都是如钻石般闪亮,但来自日本的近藤麻理...
    王霞般若阅读 294评论 0 3
  • 说实话我有一种病,一种叫做假期旅行综合症的病状,因为每当接近各种假期,被问的最多的就是你要去哪里玩?我承认自己的确...
    阿同学阅读 234评论 0 0