上周做了一个订单数据统计的任务,统计的是订单的新客户数量,本文做一个解题过程的记录和整理。

新客户的定义

新客户指的是选取时间段有订单,时间段之前没有订单。

比如下面的订单数据:

时间段 2月1日之前 2月1日 ~ 3月1日
客户 A,B,C A,D,E

在2月1日之前,有 A,B,C 三家企业下过订单,而2月1号到3月1号有 A,D,E 企业下过订单,找到存在2月1号到3月1号不存在 2月1号之前的客户,也就是 D,E企业就是新客户。

订单表 t_order 有如下字段:

标识id、 订单号order_sn、业务员 sales、客户 company、下单时间order_time

统计某个时间段的新客户数量(难度:简单)

比如统计2月1日3月1日的新客户,时间段起始时间和结束时间分别用 beginend 表示。

首先统计出 2月1日之前的客户数,使用 group by 做去重处理 :

select company from t_order where order_time < begin group by company

然后统计出2月1日3月1日的客户数:

select company from t_order where order_time >= begin and order_time <= end group by company

新客户是存在2月1日到3月1日,不存在2月1日之前的客户,也就是在2月1日3月1日上去除2月1日之前的客户,整合以上两个 sql 语句,可得如下 sql

select count(*) from
(select company from t_order where order_time >= begin and order_time <= end group by company) where company not in
(select company from t_order where order_time < begin group by company)

统计业务员的新客户数量(难度:中等)

在上面的基础上多添加业务员的细分统计,使用客户 做分组,先统计出时间段之前的客户:

select  company from t_order where order_time < begin group by  company

然后查询时间段之内的下单客户,使用业务员客户做分组:

select company,sales from t_order where order_time >= begin and order_time <= end group by company,sales

上图展示时间段和时间段之前的客户,相同的客户使用关联连接。其中没有关联的就是新客户,也就是C才是新客户。两个查询做连接查询再使用业务员做分组查询,可得到每个业务的新客户数:

select  toi1.sales,
sum( if(toi1.company is not null and toi2.company is null,1,0)) as new_customer
from
(select company,sales from t_order where order_time >= begin and order_time <= end group by company,sales)
toi1 left join
(select company from t_order where order_time < begin group by company) toi2 on toi1.company = toi2.company
group by toi1.sales

统计时间段内每天或者每月的新客户(难度:困难)

上面两个查询都是在统计时间段的客户的基础上排除时间段之前的数据。统计每天或者每个月的,都需要每天和之前的做对比。这里有两个解决方案。

方案一:

步骤一:统计时间段每天或者每月的客户

把客户用 group_concat 拼接起来:

select substring(order_time,1,#{subTime}) as order_time,group_concat(distinct(company)) as companys
from t_order where order_time >= begin and order_time <= end
group by substring(order_time,1,#{subTime})

步骤二:统计每天之前的客户

每一天都需要和前面的数据做比较,首先查询到每天的客户集合,遍历每天的数据再查询之前的数据,如果在当天的客户而不在之前的客户,就是新客户。因为查询要查询很多次,所以查询的时间会很长。

比如查询 2月1日到2月3日的新客户:

日期 公司集合
2月1日 A,B
2月2日 B,D
2月3日 C,E

上面有三条数据,都要循环三次查询,如果时间段比较长,查询耗时更长。

后面想到使用 union all 组合查询,在上面查询的基础上,使用 foreach 遍历每一条数据,每条数据都往前查询数据的客户集合:

     <foreach collection="list" item="list" separator=" UNION ALL ">
select #{list.order_time} as order_time,group_concat(distinct (company )) as companys from
t_order_info
where order_type=1 and amount>0 and finish_subtype not in (3,6)
and substring(order_time,1,#{subTime}) < #{list.order_time}
and company in
<foreach collection="list.companys" item="company" open="(" close=")" separator=",">
#{company}
</foreach>
</foreach>

以上的 sql 实际应该是如下格式:

select order_time,company from t_order
union all
select order_time,company from t_order
union all
select order_time,company from t_order

使用 union all 联合查询,快了很多。

步骤三:步骤一的集合去掉步骤二的集合

包含在时间段之内的数据,去掉之前的集合,也就是新客户的了。

group_concat 拼接字符,会出现不完整的情况,这是因为超过了 group_concat_max_len 值,默认是1024,增加该值即可。

方案二:升级方案

下面是2月1日之前,以及2月1日到2月3日每天的客户集合:

日期 2月1日之前 2月1日 2月2日 2月3日
公司 A,B C A,D C,D

分析

首先看2月1日的数据,客户C 是不存在2月1号之前的,所以2月1号的新客户就是C。

然后看2月2日,要找到2月2日之前的数据。

2月2日之前就是2月1日之前 + 2月1日

所以2月2日之前的数据不需要再去数据库查询,把之前的数据累加起来。

解决方案

使用 set 集合存放数据,首先把 2月1号之前的数据放入set

2月1号之前 AB 放入集合,set 不存在的就是新客户。

首先2月1号的C不在set中,所以2月1号的新客户是C。然后把C添加到集合中。

2月2日中的A在集合中,D不在集合中,所以2月2号的新客户是D。D添加到集合中。

2月3日中的C和D都存在集合中,所以2月3日没有新客户。

如果觉得文章对你有帮助的话,请点个推荐吧!

Java 统计新客户的更多相关文章

  1. Java 8新特性之旅:使用Stream API处理集合

    在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda ...

  2. Java 8 新特性-Stream更优雅的处理集合入门

    Java 8 新特性之--Stream 一. 简单介绍 Stream是Java 8提出了的一种新的对集合对象功能的增强.它集合Lambda表达式,对集合提供了一些非常便利,高效的操作,使得代码具有非常 ...

  3. Java 11 新特性介绍

    Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个 ...

  4. Java项目之客户信息管理软件

    模拟实现基于文本界面的客户信息管理软件,该软件能够实现对客户对象的插入. 修改和删除(用数组实现),并能够打印客户明细表. 项目采用分级菜单方式.主菜单如下: “添加客户”的界面及操作过程如下所示: ...

  5. 再来看看Java的新特性——Stream流

    半年前开始试着使用Java的新特性,给我印象最深的就是Stream流和Optional.其中Stream提高了看法效率,让代码看起来十分清爽. 为什么要使用流? 摘要中已经说明了,为了提高开发效率.流 ...

  6. Java 8 新特性——检视阅读

    Java 8 新特性--检视阅读 参考 Java 8 新特性--菜鸟 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的 ...

  7. Java 8 新特性:Lambda、Stream和日期处理

    1. Lambda 简介   Lambda表达式(Lambda Expression)是匿名函数,Lambda表达式基于数学中的λ演算得名,对应于其中的Lambda抽象(Lambda Abstract ...

  8. Java 8 新特性——实践篇

    Java 8 新特性--实践篇 参考 Java8新特性 重要更新:Lambda 表达式和Stream API Lambda 表达式 Lambda 表达式引入之前: 举个场景例子:当我们要对一个班级里的 ...

  9. JAVA 8 新特性实用总JAVA 8 新特性实用总结结

    JAVA 8 新特性实用总结 作为一个工作两年多的 老 程序猿,虽然一开始就使用 jdk1.8 作为学习和使用的版本,随着技术的迭代,现有的 JDK 版本从两年前到现在,已经飞速发展到了 JDK 15 ...

随机推荐

  1. 以太网在汽车行业中的挑战——灵活的接口及软件使ECU开发不再复杂

    以太网在汽车行业中的挑战--灵活的接口及软件使ECU开发不再复杂 以太网将会在一批新车型中作为一个车载系统网络使用.因此,下一步就是以太网和现有汽车网络技术的集成,包括:CAN.FlexRay.LIN ...

  2. Numpy的数学统计函数

    Numpy的数学统计函数 本节内容: 1.Numpy有哪些数学统计函数: 函数名 说明 np.sum 所有元素的和 np.prod 所有元素的乘积 np.cumsum 元素的累积加和 np.cumpr ...

  3. YACS-2022.4-银组

    https://www.iai.sh.cn/contest 2022.04 银组,理论上 \(100+100+30+100\). T1 上锁的抽屉 题目描述 有一个抽屉柜里竖排了 \(n\) 只抽屉. ...

  4. 百度离线人脸识别sdk的使用

    1.1下载sdk运行 百度离线人脸识别sdk的使用 1.2配置环境 添加至项目,可以拖动复制或者以类库形式添加face-resource此文件夹 放到根目录上一层 激活文件与所有dll引用放到根目录嫌 ...

  5. FreeRTOS+CubeMX编程实践

    一.关于FreeRTOS 1.什么是FreeRTOS? FreeRTOS是一个轻量级的操作系统.FreeRTOS提供的功能包括:任务管理.时间管理.信号量.消息队列.内存管理.记录功能等,可基本满足较 ...

  6. IOH和MCH(北桥芯片的变化)

    IOH位置架构图示意图 北桥芯片-MCH和北桥芯片-IOH区别 1.MCH是内存控制器中心的英文缩写,负责连接CPU,AGP总线和内存, 目前Intel的CPU已经把内存控制器(北桥芯片-MCH)总线 ...

  7. 启动分区查找可以通过 fdisk -l命令

    这里有两个硬盘,一个硬盘有两个分区,sda1 的boot列 带*表示是启动分区,否则为空

  8. vue--vuex 状态管理模式

    前言 vuex作为vue的核心插件,同时在开发中也是必不可少的基础模块,本文来总结一下相关知识点. 正文 1.基于单向数据流问题而产生了Vuex 单向数据流是vue 中父子组件的核心概念,props ...

  9. java的Integer中也会有缓存

    在上篇<java的自动拆箱会发生NPE>博客中接收了java中的Integer中的自动拆箱产生的NPE,其实对于所有的包装类来说都是一样的,都会产生这样的问题,大家需要举一反三,做学问学知 ...

  10. Web项目部署指南

    Web项目部署指南 本文记录了部署Vue项目到阿里云服务器上的过程,其中云服务器的操作系统是CentOS 7,Web服务器用的是nginx.因为项目涉及发送异步请求,而由Flask编写的后端应用监听的 ...