【MySQL必知必会】学习笔记Day7&1.29&D14-16章&P90-112页
12、使用子查询
(1) 子查询
- SQL还允许创建子查询,即嵌套在其他查询中的查询
- 子查询最常见的使用是在WHERE子句的IN操作符中,以及用来填充计算列
(2) 利用子查询进行过滤
- eg:列出订购物品TNT2的所有客户
- 步骤1:检索包含物品TNT2的所有订单的编号
- 步骤2:检索具有前一步骤列出的订单编号的所有客户的ID
- 步骤3:检索前一步骤返回的所有客户ID的客户信息
- 分别查询:
SELECT order_num
FROM orderitems
WHERE prod_id ='TNT2';
输出:
order_num
20005
20007
SELECT cust_id
FROM orders
WHERE order_num IN (20005,20007);
输出:
cust_id
10001
10004
SELECT cust_name,cust_contact
FROM customers
WHERE cust_id IN (10001,10004);
输出:
cust_name cust_contact
Coyote INc Y Lee
Yosemite PLace Y Sam
- 合并为子查询
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 ='TNT2'));
(3) 作为计算字段使用子查询
- eg:查询customers表中每个客户的订单总数
- 步骤1:从customers表中检索客户列表
- 步骤2:对于检索出的每个客户,统计其在orders表中的订单数目
- 首先,先看对一个客户,比如对客户10001的订单进行计数
SELECT COUNT(*) AS orders
FROM orders
WHERE cust_id = 10001;
- 为了对每个客户执行COUNT(*)计算,应该将COUNT(*)作为一个子查询
SELECT cust_name,
cust_state,
(SELECT COUNT(*)
FROM orders
WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers
ORDER BY cust_name;
注:
- WHERE orders.cust_id = customers.cust_id为完全限定列名
- 相关子查询:涉及外部查询的子查询
13、联结表
(1)联结
① 关系表
- 相同数据出现多次决不是一件好事,此因素是关系数据库设计的基础。关系表的设计就是要保证把信息分解成多个表,一类数据 一个表。各表通过某些常用的值(即关系设计中的关系)互相关联
- 外键:外键为某个表中的一列,它包含另一个表 的主键值,定义了两个表之间的关系
- 可伸缩性:能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好
② 为什么要使用联结
- 联结是一种机制,用来在一条SELECT 语句中关联表,因此称之为联结
(2)创建联结
SELECT vend_name,prod_name,prod_price
FROM vendors,products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;
① WHERE子句的重要性
- 笛卡儿积: 由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘 以第二个表中的行数。
② 内部联结
- 目前为止所用的联结称为等值联结,它基于两个表之间的相等测试。这种联结也称为内部联结。
- 上面的联结也可以用下面的语句:
SELECT vend_name,prod_name,prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id
③ 联结多个表
- eg:显示编号为20005的订单中的物品
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 = 20005;
注:性能考虑:不要联结不必要的表。联结的表越多,性能下降越厉害。
- eg :如下,前面的例子返回订购产品TNT2的客户列表,我们也可以使用联结的相同查询:
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 ='TNT2'));
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 = 'TNT2';
14、创建高级联结
(1) 使用表别名
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 = 'TNT2';
注:表别名只在查询执行中使用
(2) 使用不同类型的联结
① 自联结
eg:假如发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。
方法1:使用子查询
SELECT prod_id,prod_name
FROM products
WHERE vend_id = (SELECT vend_id
FROM products
WHERE prod_id = 'DTNTR');
- 方法2:使用联结查询
SELECT p1.prod_id,p1.prod_name
FROM products AS p1,products AS p2
WHERE p1.vend_id = p1.vend_id
AND p2.prod_id = 'DTNTR';
注:用自联结而不用子查询:自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。虽然最终的结果是相同的,但有时候处理联结远比处理子查询快得多
② 自然联结
- 无论何时对表进行联结,应该至少有一个列出现在不止一个表中(被联结的列)。标准的联结返回所有数据,甚至相同的列多次出现。自然联结排除多次出现,使每个列只返回一次。
- 自然联结是这样一种联结,其中你只能选择那些唯一的列。这一 般是通过对表使用通配符(SELECT *),对所有其他表的列使用明确的子集来完成的。
- eg:
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 = 'FB';
③ 外部联结
- 许多联结将一个表中的行与另一个表中的行相关联。但有时候会需要包含没有关联行的那些行,这种类型的联结称为外部联结
- eg:下面SELECT语句给出一个简单的内部联结。它检索所有客户及其订单
SELECT customers.cust_id, orders.order_num
FROM customers INNER JOIN orders
ON customers.cust_id = orders_cust_id;
- eg:外部联结语法类似,为了检索所有客户,包括那些没有订单的客户
(使用LEFT OUTER JOIN从FROM 子句的左边表中选择所有行)
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左边的表)
(从右边的表中选择所有行,应该使用RIGHT OUTER JOIN,如下例所示)
SELECT customers.cust_id, orders.order_num
FROM customers RIGHT OUTER JOIN orders
ON customers.cust_id = orders_cust_id;
注:
- MySQL不支持简化字符=和=的使用
- 左外部联结可通过颠倒FROM或WHERE子句中表的顺序转换为右外部联结
(3) 使用带聚集函数的联结
- 检索所有客户及每个客户所下的订单数
SELECT customers.cust_name,
customers.cust_id,
COUNT(orders.order_num) AS num_ord
FROM customers INNRT JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;
- eg:聚集函数于外联结使用,包含所有客户,甚至包含那些没有
任何下订单的客户
SELECT customers.cust_name,
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;
【MySQL必知必会】系列笔记:
【MySQL必知必会1-4章】学习笔记Day1
【MySQL必知必会5-7章】学习笔记Day2
【MySQL必知必会8-9章】学习笔记Day3
【MySQL必知必会10章】学习笔记Day4
【MySQL必知必会11-12章】学习笔记Day5
【MySQL必知必会13章】学习笔记Day6