在查询过程中执行顺序:from>where>group(含聚合)>having>order>select
当我们用到 聚合函数(sum,min,max,avg,count) 后,又需要筛选聚合结果时,having就派上用场了。

having子句与where都是设定条件筛选的语句,有相似之处也有区别。WHERE是在聚合语句执行前筛选记录的,聚合语句又要比having子句优先执行,同时having和group by是组合着用的

having与where的区别:

  1. having是在分组后对数据进行过滤。
  2. where是在分组前对数据进行过滤。
  3. having后的判断字段可以是聚合函数返回的结果、处理过的字段结果,不可以直接使用字段。
  4. where后面可以直接使用字段,不可以使用聚合函数返回的结果、处理过的字段结果。
    如:having 可以使用 count_user>10和add_date=finish_date,但不能使用gu.addtime=eb.billing_finish,而where刚好相反。

where子句:

select sum(num) as rmb from order where id>10
//只有先查询出id大于10的记录才能进行聚合语句

having子句:

select reports, count(*) from employees group by reports having count(*) > 4

对group by分组数据再次判断时要用having。上例先用 group byreports 分组聚合语句的结果,再用 having 筛选 count(*) > 4 聚合语句的结果,having条件字段是聚合函数返回的结果,having子句查询过程执行优先级别低于聚合语句。如果把上面的having换成where则会出错。
having就是来弥补where在分组数据判断时的不足。因为where执行优先级别要快于聚合语句。

一、在聚合查询中用GROUP BY对聚合结果分组.
SELECT region, SUM(population), SUM(area) FROM bbc GROUP BY region
先以region把返回记录分成多个组,这就是GROUP BY的字面含义。分完组后,然后用聚合函数对每组中的不同字段(一或多条记录)作运算。

二、 显示每个地区的总人口数和总面积.仅显示那些面积超过1000000的地区。
SELECT region, SUM(population), SUM(area)
FROM bbc
GROUP BY region
HAVING SUM(area)>1000000
在这里,我们不能用where来筛选超过1000000的地区,因为表中不存在这样一条记录。
相反,having子句可以让我们筛选分组后的各组数据

三、 having单独使用,与where类似
eg: 查询单笔订单充值金额大于1000的
SELECT regagent,amount FROM cy_pay_ok having amount>1000 ;
SELECT regagent,amount FROM cy_pay_ok where amount>1000 ;
两个查询结果一样

四、 having和LEFT JOIN结合,查询出用户创建时间和用户下单时间是同一天

1、用户注册同时进行了充值所有的结果,因为使用了LEFT JOIN,所以主表是 o_game_user_demo,从表是 o_exchange_billing

SELECT
	gu.`suid` count_user,
	DATE_FORMAT(FROM_UNIXTIME(gu.`addtime`),'%Y-%m-%d') add_date,
	DATE_FORMAT(`billing_finish`,'%Y-%m-%d') finish_date
FROM
	`o_game_user_demo` gu
LEFT JOIN `o_exchange_billing` eb ON eb.suid = gu.suid
WHERE
	gu.`last_login_time` BETWEEN 1586534400
AND 1586620799
AND eb.`status` = 1

mysql 查询 group by 以外的字段 mysql where group by_函数返回


2、如果去掉 AND eb.status = 1 ,只要 o_game_user_demo 有数据就查询出来了;如果是 INNER JOIN 的,count_user为175332、175347不被查询处理,要两个表都有数据才被查询出来。

mysql 查询 group by 以外的字段 mysql where group by_数据_02

3、根据用户每天创建时间分组( group by add_date ),查询出不同的用户数( count(DISTINCT gu.suid) count_user

SELECT
	count(DISTINCT gu.`suid`) count_user,
	DATE_FORMAT(FROM_UNIXTIME(gu.`addtime`),'%Y-%m-%d') add_date,
	...
AND eb.`status` = 1
group by add_date

mysql 查询 group by 以外的字段 mysql where group by_数据_03

4、根据用户每天创建时间、每天充值时间分组( group by add_date,finish_date ),查询出不同的用户数

SELECT
		count(DISTINCT gu.`suid`) count_user,
	DATE_FORMAT(FROM_UNIXTIME(gu.`addtime`),'%Y-%m-%d') add_date,
	...
AND eb.`status` = 1
group by add_date,finish_date

mysql 查询 group by 以外的字段 mysql where group by_数据_04

5、根据用户每天创建时间、每天充值时间分组,查询出不用的用户数;使用HAVING查询出每天创建时间等于每天充值时间( HAVING add_date=finish_date ),得到最终结果

SELECT
		count(DISTINCT gu.`suid`) count_user,
	DATE_FORMAT(FROM_UNIXTIME(gu.`addtime`),'%Y-%m-%d') add_date,
	...
AND eb.`status` = 1
group by add_date,finish_date
HAVING add_date=finish_date

mysql 查询 group by 以外的字段 mysql where group by_字段_05