(六)数据库 | 分组查询与组合查询

发布于 2021-09-08 11:29

  分组查询  GROUP BY

 组合查询UNION[ALL]


引言

数据检索是SQL中最常用也最复杂的数据操作之一,在数据库系列(三)中,我们讲述了用比较操作符、逻辑操作符和算术操作符构建最简单、最基本的检索条件,这期我们将介绍数据的分组过滤和组合查询!

分组查询

分组(GROUP BY)在日常生活中十分常见,体测时按照性别对测试者进行分组以匹配合适的检测项目,高考时按照省份对考生进行分组以匹配合适的高考试卷,在SELECT语句中利用GROUP BY和HAVING子句进行排序分组和过滤分组;

将一个表中的数据进行分组相当于将该表拆分成多个子表,例如求取每个供应商所提供的产品总数时,可以将产品先按照供应商进行分组,分组后相当于每张产品子表中的供应商相同,然后再分别进行计数即可。

查询每个供应商所提供的产品数目:

SELECT vend_id, COUNT(*) AS num_items

FROM products

GROUP BY vend_id;

特别注意

1、GROUP BY 子句必须出现在FROM子句之后,ORDERY BY子句之前;

2、如果指定的分组列中包含NULL值,则将NULL作为一个分组返回;

3、除聚集函数外,SELECT 语句中的所有列都必须在GROUP BY子句中给出!

4、GROUP BY子句中的所有列必须是自然列或自然列的有效表达式,但不能是聚集函数,若在SELECT中使用了表达式,则GROUP BY子句中也必须包含该表达式

5、GROUP BY子句可以包含任意数目的列(如对于student表指定grade, class和gender三个列作为分组列),即可以建立嵌套分组,嵌套分组指定的所有列一起计算(即只有grade, class和gender都相同时才被归为同一组)。



过滤分组

如果我们想让返回结果中仅含供应产品数大于2的供应商怎么办呢?我们知道,WHERE子句可以通过指定检索条件来过滤行,在分组查询中的HAVING子句也可以通过指定检索条件来过滤分好的组,并且WHERE子句和HAVING子句的检索条件的构建语法是完全一样的,但过滤分组往往需要利用聚集函数来构建过滤条件。

查询订单在两单以上的客户ID:

SELECT cust_id, COUNT(*)

FROM orders

GROUP BY cust_id

HAVING COUNT(*) >= 2;

特别注意

1、在同时使用WHERE和HAVING时,WHERE子句先执行,即先用WHERE子句过滤掉不符合检索条件的行,然后再在剩下的行组成的表中进行分组;

2、GROUP BY子句在进行分组时往往按照一定的顺序并返回分组结果,但这不一定是你所想要的排序结果,所以在需要对分组结果排序时,不能遗漏ORDER BY;

请看例子,查询05年9月份订单总价大于等于50美元的订单号及订单总价格:

SELECT order_num, SUM(quantity*item_price) AS ordertotal

FROM orderitems
WHERE order_num IN
(SELECT order_num 
FROM orders 
WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30') 
# 利用子查询检索9月份订单,注意order_date数据类型为时间日期型
GROUP BY order_num
HAVING ordertotal >= 50
ORDER BY order_num;
SELECT oi.order_num, SUM(quantity*item_price) AS ordertotal
FROM orderitems AS oi, orders AS o
WHERE oi.order_num = o.order_num AND 
Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30'
# 建立联结表后直接检索9月份订单
GROUP BY order_num
HAVING ordertotal >= 50
ORDER BY order_num;

这里首先使用WHERE子句和子查询或联结查询检索出05年9月份的订单,然后用GROUP BY按照订单号分组并统计每个订单的总价格,并用HAVING子句过滤到总价低于50美元的订单,最后用ORDER BY对检索结果按照订单号进行排序以完成查询任务。

组合查询

组合查询:使用UNION关键字组合多条SELECT语句,并将它们的查询结果合并返回成一个结果集。

使用方式:直接将UNION关键字放在两条或多条SELECT语句之间即可,也可以在UNION后使用ALL关键字声明不删除多个查询结果集中出现的重复的行(大多数情况是不需要重复行的,所以默认删除重复行,即一般不使用ALL进行声明)


注意

1、因为在查询时不存在对结果集进行“部分排序“而另一部分不排序的情况,所以ORDERY BY子句仅能使用一次,在组合查询中若要排序则只能在最后一个SELECT语句中使用ORDER BY子句;

2、UNION查询中的每个SELECT查询必须包含相同的列或表达式、聚集函数。

3、UNION组合查询的性能比OR高,当构建检索条件需要使用多个OR时不妨将该查询转换为组合查询,这在查询大量数据的复杂查询中非常有用!

查询商品价格小于等于5或由供应商1001和1002供应的商品

并供应商ID和商品价格升序排列:

SELECT vend_id, prod_id, prod_price

FROM products

WHERE prod_price <= 5

UNION

SELECT vend_id, prod_id, prod_price

FROM products

WHERE vend_id IN (1001, 1002)

ORDER BY vend_id, prod_price;

SELECT vend_id, prod_id, prod_price

FROM products

WHERE prod_price <= 5 OR vend_id IN (1001, 1002)

ORDER BY vend_id, prod_price;

# 似乎所有的组合查询都可以和OR连接的检索互换,但组合查询能够使得负责查询更加简介、容易理解,更重要的是它的速度比OR快!

END

分组查询:GROUP BY 分组列名, HAVING 组过滤条件

组合查询:UNION [ALL]

统计美学
专注于数据分析和统计应用的学习平台
28篇原创内容

本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。

相关素材