《SQL必知必会》笔记6-子查询、联结表join

1 使用子查询

查询(query):任何SQL语句都是查询,但一般指SELECT语句。

SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询。

1.1 利用子查询进行过滤

在使用GROUP BY子句前,需要知道一些重要的规定。

订单存储在连个表中。每个订单包含订单编号、顾客ID、订单日期,在Orders表中存储为一行,各订单的物品存储在相关的OrderItems表中。Orders表不存储顾客信息,只存储顾客ID。顾客的实际信息存储在Customers表中。

现在,假如需要列出订购物品RGAN01的所有顾客,应该怎样检索?下面列出具体的步骤。

  • 检索包含物品RGAN01的所有订单的编号。
  • 检索具有前一步骤列出的订单的所有顾客的ID。
  • 检索前一步骤返回的所有顾客ID的顾客信息。

3小步:

SELECT order_num 
FROM OrderItems
WHERE prod_id = 'RGAN01';

SELECT cust_id 
FROM Orders
WHERE order_num IN (20007, 20008);

SELECT cust_name, cust_contact 
FROM Customers
WHERE cust_id IN ('1000000004', '1000000005');

一步搞定:

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 = 'RGAN01'));

为了执行上述SELECT语句,DBMS实际上必须执行三条SELECT语句。最里边的子查询返回订单号列表,此列表用于其外面的子查询的WHERE子句。外面的子查询返回顾客ID列表,此顾客ID列表用于最外层查询的WHERE子句。最外层查询返回所需的数据。

可见,在WHERE子句中使用子查询能够编写出功能很强且很灵活的SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于性能的限制,不能嵌套太多的子查询。

注意:作为子查询的SELECT语句只能查询单个列。企图检索多个列将返回错误。


1.2 作为计算字段使用子查询

使用子查询的另一个方法是创建计算字段。

假如需要显示Customers表中每个顾客的订单总数。订单与相应的顾客ID存储在Orders表中。

执行这个操作,要遵循下面的步骤:

  1. 从Customers表中检索顾客列表。
  2. 对于检索出的每个顾客,统计其在Orders表中的订单数目。
SELECT cust_name, cust_state,
       ( SELECT COUNT(*) 
         FROM Orders
         WHERE Orders.cust_id = Customers.cust_id ) AS orders
FROM Customers
ORDER BY cust_name;

这里要采用完全限定列名,一个在Customers中,另一个在Orders中。

比较的是Orders表中的cust_id和当前正从Customers表中检索的cust_id:WHERE Orders.cust_id = Customers.cust_id。

如果不采用完全限定列名,会返回错误的结果。

SELECT cust_name, cust_state,
       ( SELECT COUNT(*) 
         FROM Orders
         WHERE cust_id = cust_id ) AS orders
FROM Customers
ORDER BY cust_name;

2 联结表JOIN

2.1 联结join

关系表的设计就是要把信息分解成多个表,一类数据一个表,各表通过某些共同的值互相关联(所以才叫关系数据库)。

如果数据存储在多个表中,怎样用一条SELECT语句就检索出数据呢?答案就是使用联结。

简单说,联结是一种机制,用来在一条SELECT语句中关联表,因此称为联结。使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行。


2.2 创建联结

创建联结很简单,指定要联结的所有表以及关联它们的方式即可。

SELECT vend_name, prod_name, prod_price
FROM Vendors, Products
WHERE Vendors.vend_id = Products.vend_id;

在一条SELECT语句中联结几个表时,相应的关系是在运行中构造的。在联结两个表时,实际要做的事将第一个表中的每一行与第二个表中的每一行配对。WHERE子句作为过滤条件,只包含那些匹配给定条件(这里是联结条件)的行。没有WHERE子句的话,第一个表中的每一行将与第二个表中的每一行配对,而不管它们逻辑上是否能陪在一起。

SELECT vend_name, prod_name, prod_price
FROM Vendors, Products;

返回的数据用每个供应商匹配了每个产品,包括了供应商不正确的产品。这些数据,显然不是我们想要的。


2.3 内联结(inner join)

目前为止,使用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内联结(inner join)。内联结是最常用的联结方式。

SELECT vend_name, prod_name, prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;

2.4 联结多个表

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 = 20007;

联结的表越多,性能下降越厉害。

使用子查询:

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 = 'RGAN01'));

联结查询:

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

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

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

推荐阅读更多精彩内容