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表中。
执行这个操作,要遵循下面的步骤:
- 从Customers表中检索顾客列表。
- 对于检索出的每个顾客,统计其在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';
如果您发现文中有不清楚或者有问题的地方,请在下方评论区留言,我会根据您的评论,更新文中相关内容,谢谢!