商品信息表tb_product_info
id | product_id | shop_id | tag | int_ | quantity | release_time |
1 | 8001 | 901 | 日用 | 60 | 1000 | 2020-01-01 10:00:00 |
2 | 8002 | 901 | 零食 | 140 | 500 | 2020-01-01 10:00:00 |
3 | 8003 | 901 | 零食 | 160 | 500 | 2020-01-01 10:00:00 |
4 | 8004 | 902 | 零食 | 130 | 500 | 2020-01-01 10:00:00 |
(product_id-商品ID, shop_id-店铺ID, tag-商品类别标签, in_price-进货价格, quantity-进货数量, release_time-上架时间)
订单总表tb_order_overall
id | order_id | uid | event_time | total_amount | total_cnt | status |
1 | 301002 | 102 | 2021-10-01 11:00:00 | 235 | 2 | 1 |
2 | 301003 | 101 | 2021-10-02 10:00:00 | 300 | 2 | 1 |
3 | 301005 | 104 | 2021-10-03 10:00:00 | 160 | 1 | 1 |
(order_id-订单号, uid-用户ID, event_time-下单时间, total_amount-订单总金额, total_cnt-订单商品总件数, status-订单状态)
订单明细表tb_order_detail
id | order_id | product_id | price | cnt |
1 | 301002 | 8001 | 85 | 1 |
2 | 301002 | 8003 | 180 | 1 |
3 | 301003 | 8004 | 140 | 1 |
4 | 301003 | 8003 | 180 | 1 |
5 | 301005 | 8003 | 180 | 1 |
(order_id-订单号, product_id-商品ID, price-商品单价, cnt-下单数量)
问题:请计算2021年10月商城里所有新用户的首单平均交易金额(客单价)和平均获客成本(保留一位小数)。
注:订单的优惠金额 = 订单明细里的{该订单各商品单价×数量之和} - 订单总表里的{订单总金额} 。
输出示例:
示例数据的输出结果如下
avg_amount | avg_cost |
231.7 | 23.3 |
解释:
2021年10月有3个新用户,102的首单为301002,订单金额为235,商品总金额为85+180=265,优惠金额为30;
101的首单为301003,订单金额为300,商品总金额为140+180=320,优惠金额为20;
104的首单为301005,订单金额为160,商品总金额为180,优惠金额为20;
平均首单客单价为(235+300+160)/3=231.7,平均获客成本为(30+20+20)/3=23.3
示例1
输入
DROP TABLE IF EXISTS tb_order_overall; CREATE TABLE tb_order_overall ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID', order_id INT NOT NULL COMMENT '订单号', uid INT NOT NULL COMMENT '用户ID', event_time datetime COMMENT '下单时间', total_amount DECIMAL NOT NULL COMMENT '订单总金额', total_cnt INT NOT NULL COMMENT '订单商品总件数', `status` TINYINT NOT NULL COMMENT '订单状态' ) CHARACTER SET utf8 COLLATE utf8_bin; DROP TABLE IF EXISTS tb_product_info; CREATE TABLE tb_product_info ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID', product_id INT NOT NULL COMMENT '商品ID', shop_id INT NOT NULL COMMENT '店铺ID', tag VARCHAR(12) COMMENT '商品类别标签', in_price DECIMAL NOT NULL COMMENT '进货价格', quantity INT NOT NULL COMMENT '进货数量', release_time datetime COMMENT '上架时间' ) CHARACTER SET utf8 COLLATE utf8_bin; DROP TABLE IF EXISTS tb_order_detail; CREATE TABLE tb_order_detail ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID', order_id INT NOT NULL COMMENT '订单号', product_id INT NOT NULL COMMENT '商品ID', price DECIMAL NOT NULL COMMENT '商品单价', cnt INT NOT NULL COMMENT '下单数量' ) CHARACTER SET utf8 COLLATE utf8_bin; INSERT INTO tb_product_info(product_id, shop_id, tag, in_price, quantity, release_time) VALUES (8001, 901, '日用', 60, 1000, '2020-01-01 10:00:00'), (8002, 901, '零食', 140, 500, '2020-01-01 10:00:00'), (8003, 901, '零食', 160, 500, '2020-01-01 10:00:00'), (8004, 902, '零食', 130, 500, '2020-01-01 10:00:00'); INSERT INTO tb_order_overall(order_id, uid, event_time, total_amount, total_cnt, `status`) VALUES (301002, 102, '2021-10-01 11:00:00', 235, 2, 1), (301003, 101, '2021-10-02 10:00:00', 300, 2, 1), (301005, 104, '2021-10-03 10:00:00', 160, 1, 1); INSERT INTO tb_order_detail(order_id, product_id, price, cnt) VALUES (301002, 8001, 85, 1), (301002, 8003, 180, 1), (301003, 8004, 140, 1), (301003, 8003, 180, 1), (301005, 8003, 180, 1);
输出
231.7|23.3
select round(avg(total_amount),1) avg_amount,round(avg(sum_price-total_amount),1) avg_cost from ( select tod.order_id ,uid ,product_id ,event_time ,total_amount ,row_number() over(partition by uid order by event_time) rk ,sum(price*cnt) over(partition by order_id) sum_price ,status from tb_order_detail tod left join tb_order_overall too on tod.order_id = too.order_id where status = 1 ) t where rk = 1 and date_format(event_time,'%Y-%m')='2021-10' #需要聚合的变量不能和不需要聚合的一起算 #需要先在子表里聚合之后一起不聚合地算 #第九行不能用rank()得用row_number,因为体现不同的product_id只会用于计算price*cnt #但这时还没筛选,所以不怕丢数据,算完乘积之后两行就没有区别了,要用row_number()去重
编辑于 2022-01-06 19:17:28
回复(9)
本题需要注意的点:
①10月份的新用户------即顾客的首次下单时间在‘2021-10’
②首单----10月份第一次下单的相关数据
select round(avg(total_amount),1) avg_amount, round(avg(sum1-total_amount),1) avg_cost from (select order_id,uid,event_time,total_amount, row_number() over (partition by uid order by event_time) t_rank from tb_order_overall where status=1 ) as a inner join (select order_id,sum(price*cnt) sum1 from tb_order_detail group by order_id) d on d.order_id=a.order_id where a.t_rank=1 and date_format(a.event_time,'%Y-%m')='2021-10'
发表于 2021-12-07 08:48:58
回复(0)
1.先计算出每个uid在10月份最早购买的订单
2.求出需要的值,为后面的计算做准备
with t as( select order_id, avg(total_amount) total_amount, sum(price*cnt)-avg(total_amount) diff from tb_order_overall t1 left join tb_order_detail t2 using(order_id) where month(event_time)='10' and (uid,event_time) in ( select uid,min(event_time) from tb_order_overall group by uid ) group by order_id ) select round(avg(total_amount),1) avg_amount, round(avg(diff),1) avg_cost from t;
发表于 2022-02-25 23:58:57
回复(1)
#2021年10月所有新用户和首单时间 with t as(select uid,min(event_time) as f_order_time from tb_order_overall join tb_order_detail using(order_id) group by uid having date_format(f_order_time,"%Y-%m")="2021-10"), #客单价 t1 as(select round(sum(total_amount)/count(uid),1) as avg_amount from t join tb_order_overall using(uid)), #每个订单原总价 t2 as(select order_id,sum(price*cnt) as total_price from tb_order_detail join tb_order_overall using(order_id) group by order_id), #平均获客成本 t3 as(select round(sum(total_price-total_amount)/count(*),1) as avg_cost from tb_order_overall join t2 using(order_id) where (uid,event_time)in(select*from t)) select avg_amount,avg_cost from t1,t3
请教大家一个问题,
为什么当查询一列时,avg_amount就是对的
select avg_amount from t1,t3
而查询两列时,就是错的了呢
select avg_amount,avg_cost from t1,t3
发表于 2022-02-19 11:31:42
回复(7)
比较简单的方法,值得一试
一.首单与用户
(uid,event_time) in(select uid,min(event_time) as first_order_time from tb_order_overall group by uid)
一.将tb_order_detail与tb_order_overall联结起来
with t1 as(select t3.order_id,max(total_amount) total_amount,sum(price*cnt) as total_price
from tb_order_detail as t3 inner join tb_order_overall as t2 on t3.order_id=t2.order_id
where date_format(event_time,'%Y-%m')='2021-10'
from tb_order_detail as t3 inner join tb_order_overall as t2 on t3.order_id=t2.order_id
where date_format(event_time,'%Y-%m')='2021-10'
and (uid,event_time) in(select uid,min(event_time) as first_order_time from tb_order_overall group by uid)
group by t3.order_id)
group by t3.order_id)
三.算出avg_amount与avg_cost
select round(avg(total_amount),1) as avg_amount,round(avg(total_price-total_amount),1) as avg_cost from t1
合并
with t1 as(select t3.order_id,max(total_amount) total_amount,sum(price*cnt) as total_price
from tb_order_detail as t3 inner join tb_order_overall as t2 on t3.order_id=t2.order_id
where date_format(event_time,'%Y-%m')='2021-10'
from tb_order_detail as t3 inner join tb_order_overall as t2 on t3.order_id=t2.order_id
where date_format(event_time,'%Y-%m')='2021-10'
and (uid,event_time) in(select uid,min(event_time) as first_order_time from tb_order_overall group by uid)
group by t3.order_id)
group by t3.order_id)
select round(avg(total_amount),1) as avg_amount,round(avg(total_price-total_amount),1) as avg_cost from t1;
发表于 2022-05-05 17:53:19
回复(0)
SELECT round(sum(total_amount)/count(1),1),round(sum(f)/count(1),1) FROM (SELECT order_id,uid,total_amount,s,s-total_amount f FROM tb_order_overall --联立订单明细表 算出优惠了多少 LEFT JOIN ( --算出订单表的原本总额 SELECT order_id,SUM(cnt*price) s FROM tb_order_detail GROUP BY order_id ) t1 USING(order_id) --过滤掉日期不对的和不是新用户订单的 WHERE date_format(event_time,'%Y-%m')='2021-10' AND (uid,event_time) IN (SELECT uid,MIN(event_time) FROM tb_order_overall GROUP BY uid))t2;
发表于 2022-03-10 10:09:52
回复(0)
select round(avg(avg1),1) as avg_amount ,round(avg(sum2-avg1),1) as avg_cost from ( select order_id,avg(total_amount)avg1,sum(price*cnt)sum2 from (select order_id,uid,total_amount,event_time,rank() over(partition by uid order by event_time) as ranking from tb_order_overall)t join tb_order_detail using(order_id) join tb_product_info using(product_id) where date_format(event_time,'%Y%m')='202110' and ranking=1 and uid not in (select uid from tb_order_overall where date_format(event_time,'%Y%m')<'202110' ) group by order_id)t1
思路就是算出10月每个人的首单,然后利用筛选去掉在10月前活跃过的用户。
然后计算他们的总额和优惠额即可。
发表于 2022-08-26 15:49:59
回复(0)
select round(avg(price_1), 1) as avg_amount, round(avg(price_0-price_1), 1) as avg_cost from ( select uid, sum(price*cnt) as price_0, max(total_amount) as price_1 from ( select uid, a.order_id, event_time, a.product_id, price, cnt, total_amount, dense_rank() over(partition by uid order by event_time) as rnk from tb_order_detail a left join tb_order_overall b on a.order_id = b.order_id where status = 1 ) t1 where rnk = 1 and date_format(event_time, '%Y-%m') = '2021-10' group by uid ) t2
发表于 2022-04-06 21:18:55
回复(0)
with base as (select order_id,uid,total_amount,left(event_time,7) month, rank()over(partition by uid order by left(event_time,10)) arank from tb_order_overall) select round(sum(to_am)/count(uid),1) avg_amount,round(sum(pr_am)/count(uid),1) avg_cost from (select uid,sum(total_price) to_p,sum(total_amount) to_am, sum(total_price)-sum(total_amount) pr_am from base join (select order_id,sum(price*cnt) total_price from tb_order_detail group by order_id)a using(order_id) where month='2021-10' and arank=1 group by uid)b
发表于 2022-03-28 22:09:30
回复(0)
with new_tab as (select uid,a.order_id,event_time,total_amount,price,cnt ,row_number()over(partition by uid order by event_time) as rank2 from tb_order_overall a left join tb_order_detail b on a.order_id=b.order_id) select round(avg(amount),1),round(avg(cost),1) from (select uid ,round(sum(total_amount)/count(uid)) as amount ,round(sum(price*cnt)-sum(total_amount)/count(uid)) as cost from new_tab where (uid,order_id) in (select uid,order_id from new_tab where substring(event_time,1,7)='2021-10' and rank2=1) group by uid,order_id) t
发表于 2022-03-22 16:21:05
回复(0)
with t as ( select uid, event_time, total_amount, price, cnt, rank() over(partition by uid order by event_time) rk from tb_order_overall oo join tb_order_detail od on oo.order_id = od.order_id ) select distinct round(avg(avg(total_amount)) over(),1) avg_amount, round(avg(sum(price * cnt) - avg(total_amount)) over(),1) avg_cost from t where date_format(event_time,'%Y-%m') = '2021-10' and rk = 1 group by uid
发表于 2023-09-14 21:34:05
回复(0)
跟一位发布的题解代码思路一样,他的代码可以通过,但是我的自测数据没问题,但是一提交就不行
select round(avg(total_amount),1) avg_amount,
round(avg(cost),1) avg_cost
from(
select b.order_id,
a.total_amount, #订单金额
(sum(b.price*b.cnt)-a.total_amount) as cost
from tb_order_overall a #订单总表
inner join tb_order_detail b #订单明细表
on a.order_id=b.order_id
where (a.uid,a.event_time) in (select uid,min(a.event_time) dt
from tb_order_overall
group by uid) #新用户首单下单日期
and date_format(a.event_time,'%Y-%m')='2021-10'
group by b.order_id, a.total_amount )t;
发表于 2023-08-20 15:08:51
回复(1)
哪位大佬帮我看一下,最后几行代码,在round保留1位小数时始终得不到想要的值,但保留2位小数时,除了位数不对,其他都是对的,纳闷了好久,不知其解
with t1 as
(select uid, event_time,(row_number() over (partition by uid order by event_time desc)) as rn
from tb_order_overall
),
t2 as
(select uid,tb_order_overall.order_id as order_id,event_time,total_amount,product_id,price*cnt as sell_price,(dense_rank() over (partition by uid order by event_time desc)) as rn1
from tb_order_detail left join tb_order_overall on tb_order_detail.order_id=tb_order_overall.order_id
where uid in
(select uid
from t1
where rn=1 and date_format(event_time,'%Y%m')='202110')),
t3 as
(select uid,avg(total_amount) as amount,(sum(sell_price)-avg(total_amount)) as cost
from t2
where rn1=1
group by uid)
select
round(avg(amount),1) as avg_amout,
round(avg(cost),1) as avg_cost
from t3
编辑于 2023-06-04 01:24:55
回复(1)
主要是关系有点乱,需要理清楚。
我们需要的:该订单各商品单价*数量 来自tb_order_detail
平均交易金额 和 订单总金额 来自tb_order_overall
那么我们就从这两个表构造新表,通过所给公式计即可
with o1 as
(select order_id,uid,total_amount,event_time,total_cnt-- 首单的订单信息
from (select *,row_number() over(partition by uid order by event_time asc)rk from tb_order_overall) t1
where rk=1),
o2 as
(select order_id,sum(price*cnt) yf -- 每个订单的应付金额
from tb_order_detail
group by order_id)
select round(avg(total_amount),1) avg_amount, round(sum(yf-total_amount)/count(*),1) avg_cost
from o1 left join o2 on o1.order_id=o2.order_id
where date_format(event_time,'%Y-%m')='2021-10'
发表于 2023-03-13 17:36:57
回复(0)
【场景】:新用户首次行为
【分类】:聚合函数、子查询
分析思路
难点:
1.获取新用户首单的信息。使用in子查询
(1)统计每个订单的商品总金额
- [使用]:sum() group by
(2)计算2021年10月商城里所有新用户的首***均交易金额(客单价)和平均获客成本(保留一位小数)
连续的表示:日期减去排序的值相等;
[条件]:2021年10月;新用户首单
[使用]:(uid,event_time) in( )
最终结果
select 查询结果 [平均交易金额;平均获客成本] from 从哪张表中查询数据[多表] where 查询条件 [2021年10月;已付款:新用户首单]
求解代码
方法一:
with子句
with main as( #统计每个订单的商品总金额 select order_id, sum(price*cnt) as uid_cost from tb_order_detail group by order_id ) #计算2021年10月商城里所有新用户的首***均交易金额(客单价)和平均获客成本(保留一位小数) select round(avg(total_amount),1) as avg_amount, round(avg(uid_cost-total_amount),1) as avg_cost from tb_order_overall join main using(order_id) where date_format(event_time,'%Y%m') = '202110' and status = 1 and (uid,event_time) in( select uid, min(event_time) as event_time from tb_order_overall group by uid )
方法二
多表嵌套
#计算2021年10月商城里所有新用户的首***均交易金额(客单价)和平均获客成本(保留一位小数) select round(avg(total_amount),1) as avg_amount, round(avg(uid_cost-total_amount),1) as avg_cost from tb_order_overall join( #统计每个订单的商品总金额 select order_id, sum(price*cnt) as uid_cost from tb_order_detail group by order_id ) main using(order_id) where date_format(event_time,'%Y%m') = '202110' and status = 1 and (uid,event_time) in( select uid, min(event_time) as event_time from tb_order_overall group by uid )
发表于 2022-11-06 23:46:57
回复(0)
SELECT ROUND(AVG(total_amount), 1) AS avg_amount, ROUND(AVG(total - total_amount), 1) AS avg_cost FROM( SELECT uid, event_time, ROW_NUMBER() OVER (PARTITION BY uid ORDER BY event_time) AS ranking, total_amount, SUM(price*cnt) OVER (PARTITION BY order_id) AS total FROM tb_order_detail JOIN tb_order_overall USING(order_id) WHERE status = 1) TB1 WHERE ranking = 1 AND DATE_FORMAT(event_time, '%Y%m') = 202110
这道题的概念理解太难了,看错了几百次:
- 客单价和获客成本的对象是:最小下单日期min(event_time)在10月份的用户uid的第一条order_id。根据row_number可以同时筛选出符合以上条件的记录,只能是row_number ,dense_rank,rank啥的都不行~
- 一个uid在一个order_id中可能有多条记录,所以要用SUM窗口函数,单纯的聚合有可能出现一行对应多行的错误。同时窗口聚合的分组依据应该是order_id而不是uid
发表于 2022-08-07 18:04:48
回复(0)
select round(sum(total_amount)/count(1),1) avg_amount ,round(sum(cost)/count(1),1) avg_cost from (SELECT uid,total_amount,sum(price*cnt)-total_amount cost FROM tb_order_detail join tb_product_info using (product_id) join tb_order_overall using (order_id) where date(event_time) like '%2021-10%' and (uid,event_time) in (select uid ,min(event_time) from tb_order_overall GROUP BY uid ) group by uid,total_amount) t
发表于 2022-07-20 17:13:19
回复(1)
有哪个大神帮忙看看为什么这个代码通不过
with X as ( select t1.order_id , t2.uid , t2.total_amount , t1.price , row_number() over (partition by t2.uid order by t1.order_id) as rank_order , sum(price*cnt) over(partition by order_id) as sum_price , t2.status from tb_order_detail t1 left join tb_order_overall t2 on t1.order_id=t2.order_id left join tb_product_info t3 on t1.product_id=t3.product_id where date_format(t2.event_time, '%Y-%m') = '2021-10' and status = 1) select round(avg(total_amount), 1) as avg_amount , round(avg(sum_price-total_amount), 1) as avg_cost from X where rank_order=1
发表于 2022-05-09 22:44:17
回复(4)
# 超简单
#第一步找到新用户,获取必要信息
select uid,order_id,event_time,total_amount
from (
select uid,order_id,event_time,total_amount,
from (
select uid,order_id,event_time,total_amount,
row_number() over(partition by uid order by event_time) as r
from tb_order_overall
)as aa
where r=1
from tb_order_overall
)as aa
where r=1
#第二步找到新用户详细订单信息
select order_id,sum(price*cnt) as amount
from tb_order_detail
group by order_id
#第三步两个表相交,计算
select order_id,sum(price*cnt) as amount
from tb_order_detail
group by order_id
#第三步两个表相交,计算
select round(avg(total_amount),1) as avg_amount, round(avg(amount-total_amount),1) as avg_cost
from (
select uid,order_id,event_time,total_amount
from (
select uid,order_id,event_time,total_amount,row_number() over(partition by uid order by event_time) as r
from tb_order_overall
)as aa
where r=1
)as a
inner join (
select order_id,sum(price*cnt) as amount
from tb_order_detail
group by order_id
)as b
on a.order_id=b.order_id
where substr(event_time,1,7)='2021-10'
from (
select uid,order_id,event_time,total_amount
from (
select uid,order_id,event_time,total_amount,row_number() over(partition by uid order by event_time) as r
from tb_order_overall
)as aa
where r=1
)as a
inner join (
select order_id,sum(price*cnt) as amount
from tb_order_detail
group by order_id
)as b
on a.order_id=b.order_id
where substr(event_time,1,7)='2021-10'
发表于 2022-03-15 20:47:14
回复(0)