13 创建高级联结

1.使用表别名

给列起别名的语法如下(第7章),输入:

SELECT Concat(vend_name, ' (', RTRIM(vend_country), ')')

FROM Vendors

ORDER BY vend_name;

输出:

SQL除了可以对列名和计算字段使用别名,还允许给表名起别名。理由是:

缩短SQL语句;

允许在一条SELECT语句中多次使用相同的表。

对前一课的例子:

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

改为使用别名,输入:

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子句以及其他语句部分。表别名只在查询执行中使用,不返回到客户端。

2.使用不同类型的联结

除了内联结或等值联结的简单联结,有三种其他联结:自联结(self_join)、自然联结(natural join)和外联结(outer join)

(1)自联结

假设要给与Jim Jones同一公司的所有顾客发送一封信件,该查询要求首先找出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';

输出:

此查询中需要的两个表实际是相同的,因此Customers表在FROM子句中出现了两次,对Customers的引用具有歧义性,因为DBMS不知道引用的是哪个Customers表。表别名可以解决该问题。注意,SELECT语句使用c1前缀明确给出所需列的全面,否则,DBMS将返回错误。

(2)自然联结

标准联结(内联结)返回所有的数据,相同的列甚至多次出现,而自然联结排除多次出现,使每一列只返回一次。

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

输入:

SELECT C.*, O.order_num, O.order_date

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

输出:

列出了订购物品'RGAN01'的所有顾客及其信息。

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

(3)外联结

外联结包含了那些在相关表中没有关联行的行,例如:

1)对每个顾客下的订单进行计数,包括哪些至今尚未下订单的顾客;

2)列出所有产品以及订购数量,包括没有人订购的产品;

3)计算平均销售规模,包括哪些至今尚未下订单的顾客。

下面是一个简单的内联结,检索所有顾客及其订单,输入:

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;

输出:

SQL语句使用了关键字OUTER JOIN来指定连接类型,而不是在WHERE子句中指定。但必须用LEFTRIGHT关键字指定包括其所有行的表,RIGHT指的是OUTER JOIN右边的表,LEFT指的是左边的表。

为了从右边的表选择所有行,输入:

SELECT Customers.cust_id, Orders.order_num

FROM Customers RIGHT OUTER JOIN Orders

ON Customers.cust_id = Orders.cust_id;

输出:

另一种外联结——全外联结(full outer join),它检索两个表中的所有行并关联那些可以关联的行。全外联结包含两个表的不关联行。语法如下。

输入:

SELECT Customers.cust_id, Orders.order_num

FROM Customers FULL OUTER JOIN Orders

ON Customers.cust_id = Orders.cust_id;

输出:MySQL不支持FULL OUTER JOIN语法。

3.使用带聚集函数的联结

聚集函数除了从一个表汇总数据,也可以与联结一起使用。

假设要检索所有顾客即每个顾客下的订单数,使用COUNT()函数来完成,输入:

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语句使用INNER JOINCustomersOrders表互相关联,GROUP BY子句按顾客分组分组数据,因此函数调用Count(Orders.order_num)对内个顾客的订单技术,将其作为num_ord返回。

聚集函数也可以与其他联结一起使用,输入:

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;

输出:

使用左外部联结来包含所有顾客,甚至那些没有任何订单的顾客。如1000000002顾客,他有0个订单。

4.使用联结和联结条件

(1)注意所使用的联结类型,一般使用内联结,但使用外联结也有效。

(2)应该查看具体文档获得确切的联结语法。

(3)保证使用正确的联结语法,否则会返回不正确的数据。

(4)应该总是提供联结条件,否则会得出笛卡尔积。

(5)在一个联结中可以包含多个表,甚至可以对每个联结采用不同的联结类型,但是应该在一起测试它们之前分别测试每个联结。

原文地址:https://www.cnblogs.com/Sumomo0516/p/6131547.html