百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

SQL 中 HAVING 的奇妙世界(sql+中+having+的奇妙世界有哪些)

wptr33 2025-04-06 22:14 27 浏览

HAVING 在 SQL 里可重要啦,它常常跟 GROUP BY 子句一块用,能给聚合函数的结果做过滤。

在 SQL 查询里,GROUP BY 子句能把数据按特定的列分好组。HAVING 子句就在分组完了以后起作用,它能根据聚合函数的结果,把满足特定条件的组挑出来。比如说,在一个卖东西的数据表里头,咱们能靠 GROUP BY 按销售员来分组,然后用 HAVING 子句把总销售额超过一定数的销售员选出来。

HAVING 子句的作用主要在这么几个地方:头一个,它能对聚合函数算出来的结果输出做限制。好比说,咱们可能就只想看销售总额超过 1500 美元的商店信息,这时候就得用 HAVING 子句。语法格式一般是这样:SELECT "column_name1", SUM ("column_name2") FROM "table_name" GROUP BY "column_name1" HAVING (arithematic function condition)。

HAVING 子句被限制在 SELECT 语句里已经定义好的列和聚合表达式上头。通常,咱们得在 HAVING 子句里再重复一遍聚合函数表达式来引用聚合的值,就跟在 SELECT 语句里做的一样。比如说:SELECT A COUNT (B) FROM TABLE GROUP BY A HAVING COUNT (B)>2。

反正,HAVING 在 SQL 里给咱们提供了一个厉害的工具,能对分组以后的聚合结果做精准的筛选,这样就能满足各种麻烦的查询需要啦。

二、HAVING 与 WHERE 的区别

(一)作用的阶段不一样

WHERE 子句是在数据分组前给原始数据做过滤,就是说它在查询刚开始的时候起作用,用来限制进入分组和聚合操作的数据。比如说,在一个卖东西的数据表里,如果咱们想找销售额大于 1000 的记录,在分组前就能用 WHERE 子句来筛选,像 SELECT product_id, SUM(quantity) AS total_quantity FROM sales WHERE sales_amount > 1000 GROUP BY product_id;,这个查询就只给销售额大于 1000 的记录做分组求和。

可 HAVING 子句是在数据分组以后给分组结果做过滤,就是说它在 GROUP BY 子句后面起作用,用来限制最终结果里的分组。比如 SELECT product_id, SUM(quantity) AS total_quantity FROM sales GROUP BY product_id HAVING SUM(quantity)>100;,这个查询会对所有产品按 product_id 分组求和,然后只给出总数量大于 100 的分组。

(二)使用的限制不一样

WHERE 子句能对单个的记录做条件判断,比如说对列值的具体数字做过滤,但是不能对聚合函数做判断。比如说,咱们不能写 SELECT product_id,SUM(quantity) AS total_quantity FROM sales WHERE SUM(quantity)>100 GROUP BY product_id;,这样的查询会报错,因为 WHERE 不能用聚合函数。

HAVING 子句通常是跟聚合函数(像 SUM (), AVG (), COUNT () 这些)一块用,对分组后的结果做条件判断。比如 SELECT customer_id, SUM(sales_amount) AS total_sales FROM sales GROUP BY customer_id HAVING SUM(sales_amount)>10000;,这个查询会把所有销售总额超过 10000 的客户返回。

反正,WHERE 和 HAVING 在 SQL 查询里都挺重要的,不过因为它们作用的阶段和使用的限制不一样,咱们得按照具体的查询需要来选合适的子句。

三、HAVING 的常见用法

(一)跟聚合函数一块用

HAVING 经常跟聚合函数一块用,发挥出很强的筛选作用。比如说,在一个卖东西的数据表里,咱们想查平均销售额超过 5000 的客户信息。能这么写 SQL 语句:SELECT customer_id, AVG(sales_amount) AS avg_sales FROM sales_data GROUP BY customer_id HAVING AVG(sales_amount)>5000;。在这,靠 AVG 聚合函数算出每个客户的平均销售额,然后用 HAVING 子句把平均销售额大于 5000 的客户挑出来。根据一些实际例子的数据统计,要是销售数据表有 1000 个客户的记录,当中满足平均销售额超过 5000 的客户可能就几十位,HAVING 子句就能准确地找出这些特定的客户信息。

(二)跟 GROUP BY 子句一块用

HAVING 跟 GROUP BY 子句一块用的时候,能对分组后的结果做有针对性的筛选。好比在一个学生成绩表里头,按照班级来分组,然后找出平均分超过 80 分的班级信息。SQL 语句是这样:SELECT class_id, AVG(score) AS avg_score FROM student_scores GROUP BY class_id HAVING AVG(score)>80;。靠 GROUP BY 子句把学生成绩按班级分好组,再用 HAVING 子句把平均分高于 80 分的班级选出来。在实际的学校成绩管理系统里,这样的查询能帮老师很快搞清楚哪些班级整体成绩比较好,方便做有针对性的教学调整。

(三)跟其他子句联合用

HAVING 能跟 WHERE 子句这些联合起来用,满足更复杂的查询需要。比如说在一个订单表里头,先靠 WHERE 子句把特定时间段里的订单记录选出来,然后再用 GROUP BY 子句按客户分组,最后用 HAVING 子句把总订单金额超过一定数的客户信息选出来。SQL 语句像这样:SELECT customer_id, SUM(order_amount) AS total_amount FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31' GROUP BY customer_id HAVING SUM(order_amount)>10000;。在这,WHERE 子句先把 2023 年的订单记录选出来,然后 GROUP BY 子句按客户分组,最后 HAVING 子句把总订单金额超过 10000 的客户选出来。这种联合使用的办法在实际的业务数据分析里特别常见,能帮咱们从复杂的数据里找出有价值的信息。

四、HAVING 的性能优化

(一)少点数据量

在用 HAVING 子句之前,尽量靠 WHERE 子句把没必要的数据给过滤掉,让处理的数据量变少点。比如说,在一个很大的销售数据表里头,咱们能先使 WHERE sales_date > '2023-01-01' 把特定时间段里的销售记录给筛出来,这么着在做分组和用 HAVING 子句筛选的时候,处理的数据量就能少好多。按照实际的数据统计,要是销售数据表有 100 万条记录,通过合理的 WHERE 子句过滤一下,可能就剩下 10 万条记录用来后面的分组和 HAVING 筛选,这样就能明显把查询性能提高。

(二)用上索引

保证在用来分组的列上弄好索引,把查询性能提上去。索引能让数据检索的速度变快,特别是处理大量数据的时候。好比在一个有客户信息和订单信息的数据库里,如果老是按客户 ID 分组还用上 HAVING 子句筛选,那在客户 ID 这列上弄个索引就能大大提高查询的效率。假设没索引的时候,查询得花 10 秒钟,弄上索引可能 2 秒钟就能把一样的查询做完。

(三)别弄复杂计算

在 HAVING 子句里别用复杂的计算和函数,这些计算可能会对性能有不好的影响。比如说,别在 HAVING 子句里用好几层嵌套的函数调用或者复杂的算术运算。要是非得做复杂计算,可以想想把计算结果存到临时表里,然后在 HAVING 子句里用临时表的列来筛选。这样能把 HAVING 子句执行时候的计算量变少,把查询性能提高。

(四)分析查询的计划

用数据库给的查询计划分析工具,瞅瞅查询的执行计划,找找可能的性能瓶颈。通过分析查询计划,咱们能知道数据库是咋执行查询的,包括用了啥索引、做了啥排序操作这些。比如说,在一个复杂的查询里,咱们可能发现数据库在执行 HAVING 子句的时候做了好多全表扫描,这可能就是性能瓶颈的地方。通过调整查询语句或者优化数据库的结构,能把查询性能变好。假设分析完查询计划,咱们发现能通过加合适的索引或者调整 WHERE 子句的条件来少做点全表扫描,这样就能把查询速度提上去。

五、HAVING 的实际应用案例

(一)找高销售额的客户

在销售数据的分析里,咱们经常得把高销售额的客户找出来。比如说在一个电商平台的销售数据库里,咱们能使下面这个 SQL 语句来找销售总额超过 100000 的客户:SELECT customer_id, SUM(sales_amount) AS total_sales FROM sales_table GROUP BY customer_id HAVING SUM(sales_amount)>100000;。假设这个电商平台有 10000 个客户,靠这个查询,咱们可能能找出几十或者几百个高销售额的客户。这些客户对平台来说是重要的客户群,能针对他们搞个性化的营销活动,把客户的满意度和忠诚度提上去。

(二)找高库存的产品

对企业的库存管理来说,清楚哪些产品库存太高或者太低特别重要。靠 HAVING 子句能很快把库存数量超过特定值的产品筛出来。好比在一个仓库管理系统里,使下面这个 SQL 语句:SELECT product_id, SUM(quantity) AS total_quantity FROM inventory_table GROUP BY product_id HAVING SUM(quantity)>500;。要是仓库里有 1000 种产品,这个查询能帮咱们把那些库存数量超过 500 的产品找出来。对这些高库存产品,企业能考虑搞促销活动或者调整生产计划,把库存成本降下来。

(三)找高绩效的员工

在人力资源管理里,评估员工的绩效是个重要的活儿。用 HAVING 子句能把绩效评分均值超过特定值的员工找出来。比如说在一个员工绩效评估系统里,使下面这个 SQL 语句:SELECT employee_id, AVG(performance_score) AS avg_score FROM performance_table GROUP BY employee_id HAVING AVG(performance_score)>4.5;。假设公司有 1000 名员工,靠这个查询能把那些绩效表现好的员工找出来。对这些高绩效员工,能给奖励或者晋升的机会,激励别的员工把绩效提上去。

(四)找高流量的网页

在网站分析里,清楚哪些网页的访问量高对优化网站的内容和布局特别重要。用 HAVING 子句能把访问次数超过特定值的网页找出来。好比在一个网站流量分析系统里,使下面这个 SQL 语句:SELECT page_url, COUNT(visitor_id) AS total_visits FROM web_traffic_table GROUP BY page_url HAVING COUNT(visitor_id)>1000;。要是网站有 10000 个页面,这个查询能帮咱们把那些访问量高的页面找出来。对这些高流量网页,能进一步分析用户的行为,优化页面的内容和布局,把用户体验提上去。

六、HAVING 的注意事项

(一)跟 GROUP BY 子句的关系

HAVING 子句一定得跟 GROUP BY 子句一块用,不能自己单着。这是因为 HAVING 是用来给分组后的结果做过滤的,而分组这个操作是 GROUP BY 子句干的。比如说,要是咱们只使 HAVING 子句,没有 GROUP BY 子句,数据库就会报错,因为没有分组的结果能让 HAVING 子句来筛选。

(二)支持的东西

HAVING 子句能使聚合函数,像 SUM、COUNT、AVG 这些。这就让咱们能按照分组后的聚合结果来做过滤。比如说,咱们能使 SELECT product_id, SUM(quantity) AS total_quantity FROM inventory_table GROUP BY product_id HAVING SUM(quantity)>500; 来找库存总量超过 500 的产品。这儿的 SUM(quantity) 就是聚合函数,HAVING 子句就照着这个聚合结果来做过滤。 HAVING 子句是用来过滤组的,不是单个的记录。它是在数据分组完了以后才用的,跟 WHERE 子句不一样,WHERE 子句是在数据分组前过滤行的。

(三)对性能的影响

因为 HAVING 子句是在数据分组以后才用的,所以它可能会对查询的性能有影响。特别是处理大量数据的时候,HAVING 子句可能会带来额外的计算和数据处理,让查询的速度变慢。

为了把 HAVING 子句的性能优化一下,咱们能做点事儿。比如说,在用 HAVING 子句之前,尽量靠 WHERE 子句把没必要的数据给过滤掉,让处理的数据量变少。同时,保证在用来分组的列上弄好索引,把查询性能提上去。别在 HAVING 子句里用复杂的计算和函数,也能少点性能上的开销。

(四)跟 WHERE 子句的差别

HAVING 子句跟 WHERE 子句的用处和功能不一样。WHERE 子句是在数据分组前过滤行的,不能用聚合函数。

可 HAVING 子句是在数据分组后过滤组的,能使聚合函数。 在选是用 WHERE 子句还是 HAVING 子句的时候,得按照具体的情况来判断。要是对单个记录做条件判断,或者在分组前过滤,就该用 WHERE 子句。要是对分组后的结果做条件判断,或者得用聚合函数来过滤,就该用 HAVING 子句。

七、HAVING 的高级用法

(一)用多个条件

SQL 的 HAVING 子句能把多个条件合起来,查满足特定要求的分组结果。比如说,下面这个 SQL 语句能找销售额大于 1000 并且订单数大于 10 的销售人员:SELECT salesman_id, SUM(sales_amount) AS total_sales, COUNT(order_id) AS total_orders FROM sales_table GROUP BY salesman_id HAVING SUM(sales_amount)>1000 AND COUNT(order_id)>10;。在这用了 SUM 和 COUNT 两个聚合函数,靠 AND 把两个条件连起来了,给分组后的销售人员做筛选。在实际用的时候,多个条件组合起来能更准地满足复杂的查询需要。假设在一个有 1000 条销售记录的数据库里,可能就只有很少的销售人员能同时满足销售额大于 1000 而且订单数大于 10 这个条件,HAVING 子句的多个条件能帮咱们很快找到这些特定的销售人员。

(二)用子查询

子查询在 HAVING 子句里能起大作用,帮咱们筛出特定的分组结果。比如说,咱们想找平均销售额比所有销售人员平均销售额高的销售人员,就能用子查询来实现。SQL 语句像这样:SELECT salesman_id, AVG(sales_amount) AS avg_sales FROM sales_table GROUP BY salesman_id HAVING AVG(sales_amount)>(SELECT AVG(sales_amount) FROM sales_table);。这儿的子查询(SELECT AVG(sales_amount) FROM sales_table)先算出所有销售人员的平均销售额,然后主查询里的 HAVING 子句把每个销售人员的平均销售额跟这个值比一比,把比平均值高的销售人员筛出来。在实际的数据分析里,子查询能根据不同的需要灵活地定筛选条件,让 HAVING 子句的功能更强。假设在一个有 50 个销售人员的数据库里,靠这个查询能找出那些销售业绩特别好的销售人员,给企业的销售管理提供有价值的信息。

八、HAVING 的使用场景

(一)显示特定地区的信息

在分析数据的时候,经常得只显示面积超过特定值的地区的总人口数和总面积。比如说,SELECT region, SUM(population), SUM(area) FROM test GROUP BY region HAVING SUM(area)>1000000;,这个 SQL 语句从叫 test 的表里,按照地区分组,然后把总面积超过 1000000 的地区挑出来,显示这些地区的名字、总人口数和总面积。假设在一个地理数据库里有 50 个不一样的地区,靠这个查询咱们能很快找出那些面积大的地区,好做进一步的分析和决定。

(二)筛选联合查询的结果

在 union 联合查询里,HAVING 能用来挑出不重复的时间段。比如说,SELECT date FROM (SELECT DISTINCT(date) FROM abc.test1 UNION ALL SELECT DISTINCT(date) FROM abc.test2 ) a GROUP BY date HAVING count(*)<=1;,这个查询从两个不同的表 abc.test1 abc.test2 date 1000 select snocount from sc where grade>=90 group by sno;,这个查询从学生成绩表 sc 里,找出成绩大于等于 90 分的课程数量,

按学生编号分组。假设学生成绩表有 1000 个学生的成绩记录,靠这个查询能知道每个学生的优秀课程数量。 能筛出至少两门成绩在特定值以上的学生。比如 select sno,count(*) from sc where grade>=90 group by sno having count(*)>2;,这个查询在上面那个的基础上,再把成绩大于等于 90 分的课程数量至少两门的学生筛出来。

能找出满足特定条件有资格的学生。比如说,select sno,avg(grade) from sc where SNO IN(SELECT SNO FROM SC WHERE GRADE>=95 AND PNO='YW') group by sno having avg(grade)>90;,这个查询先从学生成绩表中找出语文课成绩大于等于 95 分的学生编号,然后再按这些学生编号算平均成绩,把平均成绩大于 90 分的学生筛出来。

(四)比较查询

能查比特定学生平均成绩高的学生学号和平均分数。比如说,select sno,avg(grade) from sc group by sno having avg(grade)>(select avg(grade) from sc where sno=3);,这个查询从学生成绩表中,按学生编号分组算平均成绩,然后把平均成绩比学号为 3 的学生平均成绩高的学生学号和平均分数筛出来。假设学生成绩表有 500 个学生的成绩记录,靠这个查询能找出那些成绩相对好的学生,给教学评估做参考。

(五)获取维度的 topN

用 HAVING in 拿前 N 条维度项。比如说,select area,category,sales sum_index_sales_0 from(select area,category,sales from localdoc_topN t) a group by area,category,sales having area in(select areafrom(select area,sum(sales) sum_index_sales_0 from localdoc_topN group by area order by sum_index_sales_0 desc limit 2) b) limit 5000;,这个查询从叫 localdoc_topN 的表里,先按地区、类别和销售额分组,然后把地区在特定范围里的前 5000 条记录筛出来。假设这个表有 10000 条记录,靠这个查询能很快拿到特定维度的前几条数据。

用 row_number 函数拿每个维度的前 N 条数据。比如说,select area,category,index_sales_0 from(select area,category,sum(sales) index_sales_0,row_number() over(partition by area order by sum(sales) desc) rank_num from(select area,category,sales from localdoc_topN) t group by area,category) a where a.rank_num<=2 limit 5000;,这个查询通过窗口函数 row_number()给每个地区的销售额排名,然后把排名在前两位的记录筛出来,限制返回结果是 5000 条。在实际数据分析里,能按照不同的需要灵活调整排名和限制条件,拿到想要的维度数据。

相关推荐

MySQL进阶五之自动读写分离mysql-proxy

自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...

Postgres vs MySQL_vs2022连接mysql数据库

...

3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?

引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...

一文由浅入深带你完全掌握MySQL的锁机制原理与应用

本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...

验证Mysql中联合索引的最左匹配原则

后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...

MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)

目录1.索引基础...

你会看 MySQL 的执行计划(EXPLAIN)吗?

SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...

MySQL 从入门到精通(四)之索引结构

索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...

mysql总结——面试中最常问到的知识点

mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...

mysql总结——面试中最常问到的知识点(2)

首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...

MySQL基础全知全解!超详细无废话!轻松上手~

本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...

深入剖析 MySQL 中的锁机制原理_mysql 锁详解

在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...

Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析

引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...

MySQL基础篇:DQL数据查询操作_mysql 查

一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...

MySql:索引的基本使用_mysql索引的使用和原理

一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...