忆之独秀 https://blog.csdn.net/lavorange/article/details/25004181
这两天在参加阿里大数据竞赛,进入第二赛季要用到不少的SQL语句,现在才发现当时的数据库是白学了,今天就根据具体的需求来整理一下。可以把需求整理成为一道简单的题目,题目如下:
给定一个表t_alibaba_data:
user_id brand_id type visit_datetime
10944750 13451 0 0604
10944750 13451 2 0604
10944750 13451 2 0723
10944750 13451 0 0801
10944750 13451 0 0515
10944750 13451 0 0703
10944750 13451 0 0629
10944750 13451 0 0814
10944750 21110 0 0422
10944750 1131 0 0713
… … … …
其中:user_id代表用户,brand_id代表品牌,type代表操作的类型(0-点击,1-购买,2-收藏,3-购物车),visit_datetime即用户对品牌行为的时间(0415-0515,0516-0615,0616-0715,0716-0815四个月)。假设一共有10000条交易记录。
现在有这样的需求即:我现在需要对用户user_id对某一个品牌brand_id进行评分grade(可以理解为用户对品牌的喜爱程度),评分grade规则为用户对品牌不同类型type=0,1,2,3的操作总数,然后给这些总数乘以相应的权值grade = w0*count(type=0) + w1*count(type=1) + w2*count(type=2)+w3*count(type=3)。当然考虑到时间的因素,可以对靠后时间的点击操作提高权重,相对距离较远的点击操作降低权重,那么w0*count(type=0)可以改写成
w0*( 1*count(type=0 and 0716<=visit_datatime<=0815) + 0.8*count(type=0 and 0616<=visit_datatime<=0715) +
0.6*count(type=0 and 0516<=visit_datetime<=0615) + 0.4*count(type=0 and 0415<=visit_datetime<=0515)).现在就是要创建一个表user_brand_grade<user_id,brand_id,grade>,按照grade降序排列以便找到前1000个<user_id,brand_id>对。
Step1:首先不考虑时间的因素,首先要找到用户user_id对于某个品牌brand_id某种操作type=0/1/2/3的总次数。
SELECT user_id , brand_id , count(type=0) as type0 ,count(type=1) as type1 , count(type=2) as type2 ,count(type=3) as type3 FROM t_alibaba_data t
where visit_datetime >= 415 && visit_datetime <= 715
group by user_id,brand_id;
结果:
当我这么写完之后我发现type0,type1,type2,type3的值都是一样的。这非常不合理,才知道这么写是有问题的。
SQL语句count()的用法:http://www.w3school.com.cn/sql/sql_func_count.asp
可见count只能计算某一列的总数目,或者某一列符合一个条件的总数目,但不能计算某列符合多个条件的相应数目。
Step2:那么修改count成为sum加上type的条件可以做出相应的选择。
SELECT user_id , brand_id ,
sum(type=0) as type0,
sum(type=1) as type1,
sum(type=2) as type2,
sum(type=3) as type3
FROM t_alibaba_data t
where visit_datetime >=515 && visit_datetime <=815
group by user_id ,brand_id;
结果:
SQL语句sum()的用法:http://www.w3school.com.cn/sql/sql_func_sum.asp
sum中是可以加表达式的,因此可以加上type的相应值。
Step3:此时不禁要想,如果当type=0的时候,要根据visit_datetime选择不同的值怎么办?在此要用到case进行条件的选择。那么就可以重写Step2的SQL语句。
SELECT user_id , brand_id ,
sum(case when type=0 then 1 else 0 end) as type0,
sum(case when type=1 then 1 else 0 end) as type1,
sum(case when type=2 then 1 else 0 end) as type2,
sum(case when type=3 then 1 else 0 end) as type3
FROM t_alibaba_data t
group by user_id , brand_id ;
结果(应该和上图相同):
Step4:用case增加时间上的判断:
select * ,(type0+type1+type2+type3) as grade from (
SELECT user_id , brand_id ,
sum(case
when type=0 && visit_datetime >= 801 && visit_datetime<=815 then 10
when type=0 && visit_datetime >= 716 && visit_datetime<=731 then 8
when type=0 && visit_datetime >= 701 && visit_datetime<=715 then 6
when type=0 && visit_datetime >= 616 && visit_datetime<=630 then 4
when type=0 && visit_datetime >= 601 && visit_datetime<=615 then 2
when type=0 && visit_datetime >= 516 && visit_datetime<=531 then 1
else 0
end) as type0,
sum(case when type=1 then 1 else 0 end) as type1,
sum(case when type=2 then 2 else 0 end) as type2,
sum(case when type=3 then 3 else 0 end) as type3
FROM t_alibaba_data t
group by user_id , brand_id
order by type0 desc
)a
order by grade desc limit 1000;
然后得到结果:
那么就可以找到符合要求的<user_id,brand_id>对了,即最活跃的用户品牌对。