数据库中groupby和having语法使⽤详解
有个朋友问我⼀个返话费的问题,⼤概意思是这样的:只需把表deal中所有⼿机⽤户某天充值两次以上且总⾦额超过50的⽤户充值记录查询出来,⾄于怎么进⾏返话费那不是重点。
先看看group by的语法:
SELECT column1, SUM(column2) FROM "list-of-tables" GROUP BY "column-list";
GROUP BY⼦句将集中所有的⾏在⼀起,它包含了指定列的数据以及允许合计函数来计算⼀个或者多个列。
假设我们将从员⼯表employee表中搜索每个部门中⼯资最⾼的薪⽔,可以使⽤以下的SQL语句:
SELECT max(salary), dept FROM employee GROUP BY dept;
这条语句将在每⼀个单独的部门中选择⼯资最⾼的⼯资,结果将他们的salary和dept返回。
group by 顾名思义就是按照xxx进⾏分组,它必须有“聚合函数”来配合才能使⽤,使⽤时⾄少需要⼀个分组标识字段。
聚合函数有:sum()、count()、avg()等,使⽤group by⽬的就是要将数据分组进⾏汇总操作。
例如对员⼯表的操作:
select dept_id,count(emp_id),sum(salary) form employee  group by dept_id;
这样的运⾏结果就是以“ dept_id”为分类标志统计各单位的职⼯⼈数和⼯资总额。
group by的用法及原理详解
再看看having的语法:
SELECT column1, SUM(column2) FROM “list-of-tables” GROUP BY “column-list” HAVING “condition”;
这个HAVING⼦句的作⽤就是为每⼀个组指定条件,像where指定条件⼀样,也就是说,可以根据你指定的条件来选择⾏。如果你要使⽤HAVING⼦句的话,它必须处在GROUP BY⼦句之后。
例如还是对员⼯表的操作:
SELECT dept_id, avg(sal) FROM employee GROUP BY dept_id HAVING avg(salary) >= 4000;
这样的运⾏结果就是以“dept_id”为分类标志统计各单位的职⼯⼈数和⼯资平均数且⼯资平均数⼤于400
0。
下⾯开始我们的返话费查询功能的实现:
话费表deal字段有这些:
sell_no:订单编号
name:⽤户名
phone:⽤户⼿机号
amount:充值⾦额
date:充值⽇期
上边就这些有效字段,假如数据(数据纯属虚构,如有*,纯是巧合)如下:
sell_no            name        phone              amount      date
00000000001        李晓红      158********        50          2011-10-23 08:09:23
00000000002        李晓红      158********        60          2011-10-24 08:15:34
00000000003        李晓红      158********        30          2011-10-24 12:20:56
00000000004        杨轩        182********        100        2011-10-24 07:59:43
00000000005        杨轩        182********        200        2011-10-24 10:11:11
00000000006        柳梦璃      182********        50          2011-10-24 09:09:46
00000000007        韩菱纱      182********        50          2011-10-24 08:09:45
00000000008        云天河      183********        50          2011-10-24 08:09:25
把以上数据当天(2011-10-24)交过两次话费,⽽且总⾦额⼤于50的数据取出来,要取的结果如下:
00000000002        李晓红      158********        60          2011-10-24 08:15:34
00000000003        李晓红      158********        30          2011-10-24 12:20:56
00000000004        杨轩        182********        100        2011-10-24 07:59:43
00000000005        杨轩        182********        200        2011-10-24 10:11:11
因为今天(2011-10-24)李晓红和杨轩交过两次以上话费,⽽且总⾦额⼤于50,所以有他们的数据,⽽柳梦璃,韩菱纱,云天河只交过⼀次,所以没他们的数据。
我的处理思路⼤概是这样的,先把当天⽇期的记录⽤group by进⾏⼿机号分组即⼀个⼿机号为⼀组,接着⽤having⼦句进⾏过滤,把交过两次话费且话费总⾦额⼤于50的⼿机号查出来,最后⽤⼿机号和⽇期条件组合查询就能完成数据的查询,具体如下。
注意⽇期处理细节,要查询的某⼀天(yyyy-MM-dd)的所有记录mysql是这样处理的:
SELECT date_format(date,'%Y-%m-%d') from deal;
查询出符合条件( 交过两次以上话费,⽽且总⾦额⼤于50)的⼿机号:
select phone from deal where date_format(date,'%Y-%m-%d')="2011-10-24" group by phone having count(phone)>1 and sum(amount)>50;
结合⼿机号和⽇期查询出最终记录:
select * from deal where date_format(date,'%Y-%m-%d')="2011-10-24" and phone in
(select phone from deal where date_format(date,'%Y-%m-%d')="2011-10-24"
group by phone having count(phone)>1 and sum(amount)>50) order by phone;
⾥边嵌套了⼀个select语句,感觉效率低点了,谁有更⾼效的⽅法不?
附数据建库sql代码:
create database if not exists `phone_deal`;
USE `phone_deal`;
DROP TABLE IF EXISTS `deal`;
CREATE TABLE `deal` (
`sell_no` varchar(100) NOT NULL,
`name` varchar(100) default NULL,
`phone` varchar(100) default NULL,
`amount` decimal(10,0) default NULL,
`date` datetime default NULL,
PRIMARY KEY  (`sell_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `deal`(`sell_no`,`name`,`phone`,`amount`,`date`) values ('00001','李晓红','158********','60','2011-10-23 08:09:23'),('00002','李晓红','158********','

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。