zoukankan      html  css  js  c++  java
  • mysql视频练习题

    mysql视频练习题

    2个表:

    • order_info_utf.csv
    • user_info_utf.csv

    导入到mysql数据库。

    题目:

    1.统计不同月份下单的人数。

    ⚠️这里的人数是指共有多少名自然人下单,不是指“人次”。所以count()内加上distinct,去重复。

    SELECT month(paidTime), count(distinct userId) FROM test1.orderinfo
    where isPaid = "已支付"
    group by month(paidTime);
    +-----------------+------------------------+
    | month(paidTime) | count(distinct userId) |
    +-----------------+------------------------+
    |               3 |                  54799 |
    |               4 |                  43967 |
    |               5 |                      6 |
    +-----------------+------------------------+
    3 rows in set (1.23 sec)

    2.统计用户3月的回购率和复购率

    2.1复购率:本月消费1次以上的人数/本月消费的总人数。

        SELECT userid, count(userid) as ct FROM test1.orderinfo
        where isPaid = "已支付"
        and month(paidTime) = 3
        group by userid having ct > 1;

    得到一个列表:本月消费1次以上的人的id和他的消费次数的集合。

    这里使用了having筛选出消费1次以上的人的id。

    更好的方法是,查询结果显示2个列,分别储存“本月消费1次以上的人数”, “本月消费的总人数”:

    所以,需要外面再加一层,并去掉having:

    select count(if(ct > 1, 1, null)), count(1) from (
        SELECT userid, count(userid) as ct FROM test1.orderinfo
        where isPaid = "已支付"
        and month(paidTime) = 3
        group by userid) as t

    得到2个数字16916和54799,所以复购率是:30.87%

    2.2回购率:3月消费的人,又在4月进行了消费。这是一次回购:x。x除以3月消费的人数= 3月回购率。

    3月消费的人数: 54799人

    select count(1) from (
        select userid from test1.orderinfo
        where isPaid = "已支付"
        and month(paidTime) = 3
        group by userid) as user

    3月消费的人,又在4月进行了消费的人数: 13119人

    select count(1) from ( 
        select userid from test1.orderinfo
        where isPaid = "已支付"
        and month(paidTime) = 3
        group by userid) as user_3
    inner join (
        select userid from test1.orderinfo
        where isPaid = "已支付"
        and month(paidTime) = 4
        group by userid) as user_4 
    on user_3.userid = user_4.userid;

    因此最后: 13119/54799 =23.94%, 所以3月回购率是23.94%。

    2.3计算所有月份的回购率

    需要对2.2的代码进行修改。

    select * from (
        select userid, date_format(paidTime, "%Y-%m-01") as m, count(isPaid) from test1.orderinfo
        where isPaid = "已支付"
        group by userid, m)) as a
    left join (
        select userid, date_format(paidTime, "%Y-%m-01") as m, count(isPaid) from test1.orderinfo
        where isPaid = "已支付"
        group by userid, m) as b
    on a.userid = b.userid 

    上面的代码把两个完全相同的表连接,解释:

    1.子查询使用userid和date_format(paidTime, "%Y-%m-01")列进行分组。即得到的记录是用户在一个月内的消费次数。

    2.使用date_format()函数,改变格式,把日设为01,以便进行后面的DATE_SUB(start_date,INTERVAL expr unit)计算。

    然后,见完整代码:

    3.⚠️使用的是左连接left join

    4.因为使用左连接,所以可以这么增加一个筛选条件:and a.m = date_sub(b.m, interval 1 month)

    •  即让a的月份=b的月份-1.   这样就可以把:每条记录按照同一用户在3月消费记录和4月消费记录连接起来,同样4月和5月,6月和7月等等,即相邻月份进行关联,以便计算回购率。
    •  不符合条件的b表的value都是null表示。

    5. 最后的外层表用a.m进行分组,然后使用聚合函数统计a表每个月的消费人数,以及b.表每个月的消费人数。因为通过条件合并了相邻月份。所以最后得到回购率的分母和分子。

    select a.m, count(a.m),count(b.m) from (
        select userid, date_format(paidTime, "%Y-%m-01") as m, count(isPaid) from test1.orderinfo
        where isPaid = "已支付"
        group by userid, m) as a
    left join (
        select userid, date_format(paidTime, "%Y-%m-01") as m, count(isPaid) from test1.orderinfo
        where isPaid = "已支付"
        group by userid, m) as b
    on a.userid = b.userid 
    and a.m = date_sub(b.m, interval 1 month)
    group by a.m

     ⚠️

    6. 这里必须使用and,而不是where,

    • 因为where是对left join ...on..后的数据再筛选,不符合条件的就被去掉了。
    • 而and是在 on子句的内部,不符合条件的数据会用null表示。
    and a.m = date_sub(b.m, interval 1 month)

      

    3.统计男女的消费频次是否有差异

    设所有男性消费者为x, 所有男性消费者的合计消费次数是x_order,那么男性消费频次为 x_order/x

    select sex, avg(ct) from (
        select o.userid, t.sex, count(1) as ct from orderinfo as o
        inner join (
            SELECT * FROM test1.userinfo
            where sex <> "") t
        on o.userid = t.userid and o.ispaid = "已支付"
        group by o.userid, t.sex) t2
    group by sex


    4.统计多次消费的用户,第一次和最后一次消费间隔是多少

    (相当于一个消费者的消费的周期)

    首先,查询每个用户第一次消费和最后一次消费的时间,使用max, min函数:

    SELECT userid, max(paidtime), min(paidtime) FROM test1.orderinfo
    where ispaid = "已支付"
    group by userid
    having count(1) > 1

    然后,让max()减去min()但得到的是秒,所以需要使用datediff()函数,

    SELECT userid,max(paidtime), min(paidtime), datediff(max(paidtime), min(paidtime)) as interval_day FROM test1.orderinfo
    where ispaid = "已支付"
    group by userid having count(1) > 1

    最后,再加上一层:

    select avg(df) from (
        SELECT userid,max(paidtime), min(paidtime), datediff(max(paidtime), min(paidtime)) as df FROM test1.orderinfo
        where ispaid = "已支付"
        group by userid
        having count(1) > 1) t

    得到一个结果:15.6484天。

    求平均值,这是不准确的简单计算。根据用户类型,个别高消费频次用户,应该属于统计中的极值,不当算在统计样本中。

    或者改求中位数的值。


      

    5统计不同年龄段,用户的消费金额是否有差异?(将消费金额定义为每个年龄段的人均消费金额和总金额。)

    首先,得到一个每个用户所在年龄组的表t1

    然后,使用orderinfo,得到每个用户的消费总额的表t2。

    最后,把t1,t2内连接后,按照age_group分组,并使用聚合函数avg()计算每个年龄组的人均消费金额。

    select t1.age_group, cast(avg(t2.price) as decimal(10,2)) as avg_price from
        (select userid, ceil((year(now())-year(birth))/10)  as age_group from userinfo
        where birth > '1901-01-01') t1              #用'1901-01-01'去除一些脏数据
    inner join (
        SELECT userid, sum(price) as price FROM test1.orderinfo
        where isPaid = '已支付'
        group by userid) t2
    on t1.userid = t2.userid
    group by t1.age_group order by age_group

    更好的方法是使用case when:

    select t1.age_group, cast(avg(t2.price) as decimal(10,2)) as avg_price from (
        select userid,
        case 
            when (year(now())-year(birth)) <=10 then "<=10 "
            when (year(now())-year(birth)) between 11 and 20 then "10 to 20"
            when (year(now())-year(birth)) between 21 and 30 then "20 to 30"
            when (year(now())-year(birth)) between 31 and 40 then "30 to 40"
            when (year(now())-year(birth)) between 41 and 50 then "40 to 50"
            when (year(now())-year(birth)) between 51 and 70 then "50 to 70"
            when (year(now())-year(birth)) >=71 then ">=71"
        end as age_group
        from userinfo
        where birth > '1901-01-01') t1
    inner join (
        SELECT userid, sum(price) as price FROM test1.orderinfo
        where isPaid = '已支付'
        group by userid) t2
    on t1.userid = t2.userid
    group by t1.age_group order by t1.age_group 

    结果:

    +-----------+-----------+
    | age_group | avg_price |
    +-----------+-----------+
    | 10 to 20  |    846.63 |
    | 20 to 30  |   1003.96 |
    | 30 to 40  |   1178.61 |
    | 40 to 50  |   1183.59 |
    | 50 to 70  |   1099.86 |
    | <=10      |   1322.29 |
    | >=71      |   3269.92 |
    +-----------+-----------+

    6统计消费的2/8法则,消费的top20%的用户,贡献了多少额度

    首先,计算出每个用户的消费额度@total, 和总共有多少消费用户。

    然后,计算前20%的用户数量,使用limit得到这个用户范围的表格t

    最后,对t计算消费总额@top20_price,这个数值除以@total,得到0.85。即前20%的用户,贡献了85%的额度。

    select @count := count(userid), @total := sum(price) as total from (
        SELECT userid, sum(price) as price FROM test1.orderinfo
        where isPaid = '已支付'
        group by userid
        order by price desc) t; #total 318503081.54, count = 85649
     
    select @top20_percent := ceil(@count*0.2); #17130 
    
    select @top20_price :=sum(t.price) from (
        SELECT userid, sum(price) as price FROM test1.orderinfo
        where isPaid = '已支付'
        group by userid
        order by price desc
        limit 17130) t # 272203711.45
    select @top20_price/@total; #0.85

    或者:

    select @count := count(userid), @total := sum(price) as total from (
        SELECT userid, sum(price) as price FROM test1.orderinfo
        where isPaid = '已支付'
        group by userid
        order by price desc) t; #total 318503081.54, count = 85649
    --  
    select @top20_percent := ceil(@count*0.2); #17130 
    
    select sum(price)/@total from (
        select 
        row_number() over(order by price desc ) as rk,
        userid, price
        from (
            SELECT userid, sum(price) as price FROM test1.orderinfo
            where isPaid = '已支付'
            group by userid
            order by price desc) as t1
        ) as t2
    where t2.rk < @top20_percent

    这里使用row_numbe()计算函数,得到一个排名,然后用where子句得到前20%的用户的表t2,最后t2进行计算。

  • 相关阅读:
    Docker02 Docker初识:第一个Docker容器和Docker镜像
    Docker01 CentOS配置Docker
    Jenkins02:Jenkins+maven+svn集成
    Junit01 新建Maven项目
    Junit02 Junit创建及简单实现
    Jenkins01:linux+jenkins+ant+jmeter集成
    Jenkins初识03:构建定时任务
    python 协程
    python之socket 网络编程
    python 面向对象
  • 原文地址:https://www.cnblogs.com/chentianwei/p/12145896.html
Copyright © 2011-2022 走看看