昨晚一个朋友让我帮忙写一条 sql, 说是有一张订单表, 要查询出天天有多少人下单, 有多少人付款。听到这里可能不少人觉得用 group by 分组, count 和 sum统计函数,问题就解决了。例如:sql
select 下单时间,count(下单时间)as 订单数量, sum(付款金额) as 实付金额 from 订单表 group by 下单时间
可是咱们要考虑的是,用户有可能今天下订单,可是到次日或者第三天才付款。这个时候这条订单的付款数据 要算到 次日或者第三天去。有可能由于个人表达有问题,有的人没听懂,下面就贴出详细过程。函数
根据他的描述,我临时建了一张表。 固然,实际的订单表很复杂, 为了简化并突出重点,我只抽出了其中几个字段,字段名和类型也是随便写的。表结构以下:code
CREATE TABLE `tb_order` ( `id` varchar(32) NOT NULL DEFAULT '', -- id `status` varchar(20) DEFAULT NULL, -- 订单状态 `createtime` datetime DEFAULT NULL, -- 订单建立时间 `paytime` datetime DEFAULT NULL, -- 订单支付时间 `total` decimal(10,0) DEFAULT NULL, -- 订单支付金额 PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
插入的数据要涵盖实际生产的全部状况,这里总共插入了 8 条订单数据, 下单日期为 2019-03-11 至 2019-03-15 五天的数据。订单类型有blog
1. 当天下单 并 当天付款的ci
2. 当天下单 但 一直未付款的date
3. 当天下单 但 次日才付款的select
INSERT INTO `tb_order` VALUES ('1', '1', '2019-03-11 21:44:18', NULL, 100); INSERT INTO `tb_order` VALUES ('2', '2', '2019-03-12 21:44:46', '2019-03-12 21:45:12', 200); INSERT INTO `tb_order` VALUES ('3', '2', '2019-03-13 21:45:27', '2019-03-13 21:45:32', 120); INSERT INTO `tb_order` VALUES ('4', '2', '2019-03-14 21:45:49', '2019-03-14 21:46:50', 50); INSERT INTO `tb_order` VALUES ('5', '1', '2019-03-15 21:46:14', NULL, 60); INSERT INTO `tb_order` VALUES ('6', '2', '2019-03-11 21:53:36', '2019-03-12 21:53:42', 100); INSERT INTO `tb_order` VALUES ('7', '2', '2019-03-15 21:56:11', '2019-03-15 21:56:15', 60); INSERT INTO `tb_order` VALUES ('8', '2', '2019-03-12 21:57:31', '2019-03-12 21:57:37', 100);
根据咱们的问题, 咱们先找出几个关键字, 根据 “天天” 咱们想到了用 group by 对下单时间进行分组 ,而后咱们须要查询出来的字段有 “下单时间”, ”下单数量“,”付款金额“。可是咱们上面说了,付款金额这个字段比较难查,咱们暂时先忽略这个字段,因而就有了下面的 sql方法
select t.createtime, count(t.createtime) as '下单数量' from tb_order t group by DATE_FORMAT(t.createtime,'%Y-%m-%d');
此时咱们的任务完成了三分之一,接下来咱们只查询出天天订单的 ‘实付金额’, sql 以下:im
select paytime, sum(total)as '实付金额' from tb_order group by DATE_FORMAT(paytime,'%Y-%m-%d');
到这里,任务只能说完成了三分之二,由于咱们须要同时查出来‘ 订单数’ 和 ‘实付金额’ 这两个字段。既然咱们能经过对同一张表分开查的方法实现咱们的需求,那么咱们对同一张表进行表关联是否是就能够同时查出两个字段了 ?答案是 yes 。下面是完整的 sql:支付
SELECT t.createtime, COUNT(t.createtime) AS '下单数量', t1.tol AS '实付金额' FROM tb_order t LEFT JOIN ( SELECT paytime, SUM(total) AS tol FROM tb_order WHERE `status`='2' GROUP BY DATE_FORMAT(paytime,'%Y-%m-%d') ) t1 ON DATE_FORMAT(t1.paytime,'%Y-%m-%d')=DATE_FORMAT(t.createtime,'%Y-%m-%d') GROUP BY DATE_FORMAT(t.createtime,'%Y-%m-%d')
当咱们不能从同一张表同时查询出这两个字段,可是咱们能够分开查的时候,能够尝试用关联表,上面最终的 sql 很简单,把咱们分析过程的 第一步 和 第二步 的 sql,用一个 left join 链接起来,最后加上下面的条件,就解决了当天下单,隔天付款的状况。
ON DATE_FORMAT(t1.paytime,'%Y-%m-%d')=DATE_FORMAT(t.createtime,'%Y-%m-%d')