【学习06】MySQL分组查询与子查询

一、分组数据

这涉及两个新SELECT语句子句,分别是GROUP BY子句和HAVING子句。
表数据如下:
在这里插入图片描述

1.1 创建分组

输入:

SELECT vend_id,count(*) AS num_prods
FROM vendors
ORDER BY vend_id;

输出:
在这里插入图片描述

分析: 上面的SELECT语句指定了两个列,vend_id包含产品供应商的ID,num_prods为计算字段(用COUNT(*)函数建立)。GROUP BY子句指
示MySQL按vend_id排序并分组数据。GROUP BY子句指示MySQL分组数据,然后对每个组而不是整个结果集进行聚集。
注意:

  • GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制。
  • 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上
    进行汇总。换句话说,在建立分组时,指定的所有列都一起计算
    (所以不能从个别的列取回数据)
  • GROUP BY子句中列出的每个列都必须是检索列或有效的表达式
    (但不能是聚集函数)。如果在SELECT中使用表达式,则必须在
    GROUP BY子句中指定相同的表达式。不能使用别名。
  • 除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子
    句中给出。
  • 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列
    中有多行NULL值,它们将分为一组。
  • GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。

1.2 过滤分组

  除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组。例如,可能想要列出至少有两个订单的所有顾客。为得出这种数据,必须基于完整的分组而不是个别的行进行过滤。
  HAVING非常类似于WHERE。事实上,目前为止所学过的所有类型的WHERE子句都可以用HAVING来替代。唯一的差别是WHERE过滤行,而HAVING过滤分组。
  WHERE没有分组的概念

输入:

SELECT vend_id,COUNT(*) AS num_prods
FROM products
GROUP BY vend_id
HAVING COUNT(*) > 2;

输出:
在这里插入图片描述
分析:
这条SELECT语句的前3行类似于上面的语句。最后一行增加了
HAVING子句,它过滤 COUNT(*) > 2(两个产品数量)的那些
分组。

HAVING和WHERE的差别 这里有另一种理解方法,WHERE在数据
分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重
要的区别,WHERE排除的行不包括在分组中。这可能会改变计
算值,从而影响HAVING子句中基于这些值过滤掉的分组。

假如想进一步过滤上面的语句,使它返回过去12个月内具有两个以上订单的顾客。为达到这一点,可增加一条WHERE子句,过滤出过去12个月内下过的订单。然后再增加HAVING子句过滤出具有两个以上订单的分组.

为更好地理解,请看下面的例子,它列出具有2个(含)以上、价格
为10(含)以上的产品的供应商:

输入:

SELECT vend_id,COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10
GROUP BY vend_id
HAVING COUNT(*) >= 2;

输出:
在这里插入图片描述

分析:
这条语句中,第一行是使用了聚集函数的基本SELECT,它与前面的例子很相像。WHERE子句过滤所有prod_price至少为10的行。然后按vend_id分组数据,HAVING子句过滤计数为2或2以上的分组。如果没有WHERE子句,将会多检索出两行(供应商1002,销售的所有产品价格都在10以下;供应商1001,销售3个产品,但只有一个产品的价格大于等于10)

1.3 分组和排序

差别:
在这里插入图片描述
我们经常发现用GROUP BY分组的数据确实是以分组顺序输出的。但情况并不总是这样,它并不是SQL规范所要求的。此外,用户也可能会要求以不同于分组的顺序排序。仅因为你以某种方式分组数据(获得特定的分组聚集值),并不表示你需要以相同的方式排序输出。应该提供明确的ORDER BY子句,即使其效果等同于GROUP BY子句也是如此。

不要忘记ORDER BY 一般在使用GROUP BY子句时,应该也给
出ORDER BY子句。这是保证数据正确排序的唯一方法。千万
不要仅依赖GROUP BY排序数据

请看例子:它检索总计订单价格大于等于50的订单的订单号和总计订单价格

输入:

SELECT order_num, SUM(quantity * item_price) AS ordertotal
FROM orderitems
GROUP BY order_num
HAVING SUM(quantity * item_price) >= 50;

输出:
在这里插入图片描述
为按总计订单价格排序输出,需要添加ORDER BY子句,如下所示:
输入:

SELECT order_num, SUM(quantity * item_price) AS ordertotal
FROM orderitems
GROUP BY order_num
HAVING SUM(quantity * item_price) >= 50
ORDER BY ordertotal;

输出:
在这里插入图片描述
分析:
在这个例子中,GROUP BY子句用来按订单号(order_num列)分组数据,以便SUM(*)函数能够返回总计订单价格。HAVING子句过滤数据,使得只返回总计订单价格大于等于50的订单。最后,用ORDER BY子句排序输出

二、子查询

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

2.1 利用子查询进行过滤

订单存储在两个表中。对于包含订单号、客户ID、订单日期的每个订单,orders表存储一行。各订单的物品存储在相关的orderitems表中。orders表不存储客户信息。它只存储客户的ID。实际的客户信息存储在customers表中。

  • orders表
    在这里插入图片描述
  • orderitems表
    在这里插入图片描述
  • customers

在这里插入图片描述

需求: 假如需要列出订购物品TNT2的所有客户,应该怎样检索?下
面列出具体的步骤。
 (1) 检索包含物品TNT2的所有订单的编号。
 (2) 检索具有前一步骤列出的订单编号的所有客户的ID。
 (3) 检索前一步骤返回的所有客户ID的客户信息。

输入:

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语句,MySQL实际上必须执行3条SELECT语句。最里边的子查询返回订单号列表,此列表用于其外面的
子查询的WHERE子句。外面的子查询返回客户ID列表,此客户ID列表用于最外层查询的WHERE子句。最外层查询确实返回所需的数据。

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

列必须匹配 在WHERE子句中使用子查询(如这里所示),应
该保证SELECT语句具有与WHERE子句中相同数目的列。通常,
子查询将返回单个列并且与单个列匹配,但如果需要也可以
使用多个列

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

使用子查询的另一方法是创建计算字段。假如需要显示customers
表中每个客户的订单总数。订单与相应的客户ID存储在orders表中。
为了执行这个操作,遵循下面的步骤。
 (1) 从customers表中检索客户列表。
 (2) 对于检索出的每个客户,统计其在orders表中的订单数目

正如前两章所述,可使用SELECT COUNT(*)对表中的行进行计数,并
且通过提供一条WHERE子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。

为了对每个客户执行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;

输出:
在这里插入图片描述

分析: 这 条 SELECT 语句对 customers 表中每个客户返回 3 列 :
cust_name、cust_state和orders。orders是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个客户执行一次。在此例子中,该子查询执行了5次,因为检索出了5个客户。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习MySQL单表查询和多表查询时,可以按照以下实验步骤进行: 1. 准备数据库和表:首先,创建一个数据库,并在其中创建需要的表用于实验。可以使用MySQL的命令行工具或图形化界面工具(如phpMyAdmin)进行创建。 2. 插入测试数据:在创建的表中插入一些测试数据,用于后续的查询操作。确保数据量足够,能够涵盖各种查询场景。 3. 单表查询实验: - 使用SELECT语句,检索整个表中的数据。 - 使用WHERE子句,根据条件筛选数据。 - 使用ORDER BY子句,按照特定的列对结果进行排序。 - 使用LIMIT子句,限制返回的记录数量。 - 使用聚合函数(如COUNT、SUM、AVG)和GROUP BY子句,进行分组查询和统计操作。 - 使用子查询,嵌套其他查询语句进行更复杂的筛选和查询操作。 4. 多表查询实验: - 使用INNER JOIN操作,连接两个表,并检索相关联的数据。 - 使用ON条件,指定连接两个表的关联条件。 - 尝试使用LEFT JOIN、RIGHT JOIN和FULL JOIN等其他类型的JOIN操作。 - 使用别名为表和列指定简化的名称。 - 实践使用子查询进行多表查询和相关操作。 5. 组合查询实验:尝试将单表查询和多表查询结合起来,构建更复杂的查询语句。使用UNION、UNION ALL、INTERSECT和EXCEPT等操作符进行数据集合操作。 6. 进行性能测试和优化:对实验过程中的查询语句进行性能测试,并尝试优化查询性能,如添加索引、调整JOIN操作顺序等。 7. 总结和复习:对实验过程中的查询语句和结果进行总结和复习,思考不同查询方式的适用场景和优缺点。 通过以上实验步骤,你可以在实践中掌握MySQL单表查询和多表查询的基本技能。不断练习和尝试不同的查询场景,将帮助你深入理解查询语句的语法和用法,并提升你在MySQL查询方面的技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值