需求:
会员名称 会员手机号 消费次数 跨店消费 最多消费门店 总消费额(元) 最近消费时间 注册时间 注册门店
数据库表:
1 总店和分店的关系表,仅存放两者的id
2 订单表,门店code(唯一),消费金额,顾客id,创建日期
3 顾客表,顾客id,创建日期,电话(部分为空),姓名(部分为空),注册门店,创建日期(注意存在同一个手机号码对应多个顾客id,同一个手机号码在不同门店开通了会员或系统未能实时同步会员信息)
4 group表,门店code,门店名称,门店所属groupsId
分析:
最多消费门店 和 跨店消费 需要通过 同一顾客表的手机号码在不同店铺的消费总额和次数获取
对于本人而言的难点:
1 分页
2 日期区间
3 查询条件 in
解决方式:
1 从订单表order_info 通过创建日期和消费门店筛选出需要汇总的订单
新手的写法–
String sqlOrder = "select * from order_info a where a.status =1 and a.CUSTOMER_ID is not null and a.FLG_DELETED=0 "
+" and a.CREATE_TIME >= ? and a.CREATE_TIME <= ? and a.BELONG_COMPANY_ID in :belongCompanyId";
//占位符和命名 同时使用,若只执行一次是OK的,但是我要用2次,无奈只能改成下面的样子
踩坑后的写法–
String sqlOrder = "select * from order_info a where a.status =1 and a.CUSTOMER_ID is not null and a.FLG_DELETED=0 "
+" and a.CREATE_TIME >= :startDate and a.CREATE_TIME <= :endDate and a.BELONG_COMPANY_ID in (:belongCompanyId) ";
String sqlOrder1 = "select * from order_info a where a.status =1 and a.CUSTOMER_ID is not null and a.FLG_DELETED=0 "
+" and a.CREATE_TIME >= :startDate1 and a.CREATE_TIME <= :endDate1 and a.BELONG_COMPANY_ID in (:belongCompanyId1) ";
query.setParameter("startDate", startDate).setParameter("endDate",endDate).setParameter("startDate1", startDate).setParameter("endDate1",endDate).setParameterList("belongCompanyId", belongCompanyId).setParameterList("belongCompanyId1", belongCompanyId);
部分blog可能说setParameterList只能放在最后使用,其实,那只是在与占位符同时使用的情况
若你只使用命名,则无位置限制
2 考虑到最大消费门店和总消费额是两个维度的查询结果, 联查custom和sqlOrder的结果,分为两条sql执行
2.1 统计单个会员在duo家店铺的汇总销售额
group by mobile_phone
2.2 单个会员在单家店铺的汇总销售额
先 group by mobile_phone,门店code 再 group by mobile_phone
理论上,两条sql的查询结果数应该是一致,且能通过mobile_phone进行关联
注意,这是就无法考虑mobile_phone为空的情况,在group by时mobile_phone为空的会被数据库视为同一条数据,所以我联查时会把custom表的mobile_phone为空的筛选,但是部分是空字符串的筛选失败
3 join 合并查询结果,执行时间基本忽略不计,两条sql分开查询时各1.4s,join合并时2.8s,效率较高
注意:
1 union是纵向合并查询结果的 ,即 1+1=2
2 或许有人提出 两表通过where关联查询,查询结果是700条时,执行时间是4s多
3 或许有人尝试在dao层写两个方法,分别查询,然后在java合并结果,这代码复杂,就别自己为难自己了
//合并数据的sql
//sqlCha sqlPer 就是 两条sql
String sqlJoin = "select ta.CUSTOMER_ID,tb.NAME,ta.MOBILE_PHONE,tb.totalTimes,ta.chains,ta.company,tb.totalpays,tb.lastTime,tb.signTime,tb.signcomp "
+ "from("+ sqlCha +") as ta JOIN ("+ sqlPer +") as tb on ta.MOBILE_PHONE=tb.MOBILE_PHONE ORDER BY totalpays desc";
4 分页setFirstResult和setMaxResults
//注意setFirstResult是从0开始
pagelet.setDatas(query.setFirstResult(10*(pageNo-1)).setMaxResults(pagelet.getPerPageSize()).list());
考虑到翻页,所以要把查询结果总数也返回到页面
//select count 就不解释了