SQL22 统计每个学校的答过题的用户的平均答题数

用户信息表 user_profile
其中device_id指终端编号(认为每个用户有唯一的一个终端),gender指性别,age指年龄,university指用户所在的学校,gpa是该用户平均学分绩点,active_days_within_30是30天内的活跃天数.
答题情况明细表 question_practice_detail
其中question_id是题目编号,result是答题结果.

完成该查询的关键在于理解如何计算用户平均答题数.在q表中,由于存在一名用户回答多道题目的情况,因此计算时要在device_id前加上distinct去重.

select university,count(question_id)/count(distinct q.device_id) as avg_answer_cnt
from user_profile as u,question_practice_detail as q
where u.device_id=q.device_id
group by university;

SQL25 查找山东大学或者性别为男生的信息(结果不去重)

用户信息表 user_profile

由于题目要求结果不去重,因此使用union all连结两个select语句.

*union的结果是去重的.

select device_id , gender , age , gpa from user_profile where university = '山东大学' 
union all
select device_id , gender , age , gpa from user_profile where gender = 'male';

SQL26 计算25岁以上和以下的用户数量

用户信息表 user_profile

方法一:使用union all

select '25岁以下',count(device_id)
from user_profile
where age<25 or age is null
union all
select '25岁及以上',count(device_id)
from user_profile
where age>=25;

方法二:使用if函数.


if(x=n,a,b)表示如果x=n,则返回a,否则返回b.

select
if(age>=25,'25岁及以上','25岁以下' ) as age_cut,
count(device_id) as number
from user_profile
group by age_cut;

方法三:使用case函数.


case when x=n then a else b end)表示如果x=n,则返回a,否则返回b.


多条件时,case
when 条件1 then a
when 条件2 then b
when 条件3 then c
else '其他'end.

select (case when age>=25 then '25岁及以上' else '25岁以下' end) as age_cut, 
count(device_id) as number
from user_profile
group by age_cut;

SQL27 查看不同年龄段的用户明细

将用户划分为20岁以下,20-24岁,25岁及以上三个年龄段,若年龄为空返回其他.
用户信息表 user_profile

方法一:使用case函数.

select device_id,gender,
case
    when age<20 then '20岁以下'
    when age<25 then '20-24岁'
    when age>=25 then '25岁及以上'
    else '其他'
end age_cut
from user_profile;

方法二:使用if函数

select device_id, gender, 
if(age>=25,'25岁及以上',
if(age between 20 and 24,'20-24岁',
if(age<20,'20岁以下','其他'))) 
from user_profile;

SQL29 计算用户的平均次日留存率

答题情况明细表 question_practice_detail

该查询的核心在于计算用户在某天答题后第二天继续答题的概率.“平均”的含义是将前一天和次日留存的用户分别加总相除,因此需要用到聚集函数count;并且在分别计算的过程中用户id应当是唯一的,因此需要用到distinct去重.


datediff(date1,date2),返回两个日期的间隔时间.

select count(distinct q2.device_id,q2.date)/count(distinct q1.device_id,q1.date) as avg_ret
from question_practice_detail as q1 
left outer join 
question_practice_detail as q2
on q1.device_id=q2.device_id and datediff(q2.date,q1.date)=1;

SQL32 截取出年龄

用户信息表 user_profile

substring_index(s,delim,n)截取字符串s中第n次出现位置之前的字符串.当n>0表示从左向右,当n<0表示从右向左.


其次查询中因年龄后面还有性别,因此要进行 substring_index函数嵌套.

select 
substring_index (substring_index(profile,',',-2),',',1)as age,
count(device_id) as number
from user_submit
group by age;

SQL33 找出每个学校GPA最低的同学

用户信息表 user_profile

不能直接使用min(gpa),因为查询出来的最低gpa无法与device_id匹配.应使用子查询.

select device_id,university,gpa from user_profile
where gpa in 
(select min(gpa) from user_profile group by university)
group by university
order by university;

或者使用联结

select u1.device_id,u1.university,u1.gpa
from user_profile as u1 
join 
(select university,min(gpa) as gpa 
from user_profile group by university) as u2
on u1.university=u2.university and u1.gpa=u2.gpa 
order by u1.university;

SQL34 统计复旦用户8月练题情况

用户信息表 user_profile

因为有复旦用户在8月并未练题,将这部分用户一并取出需要加上条件date is null.

select u.device_id,university,count(question_id) as question_cnt,
count(if(result='right', 1, null)) as right_question_cnt
from user_profile as u 
left outer join 
question_practice_detail as q
on u.device_id=q.device_id
where university='复旦大学' and (month(date)=8 or date is null)
group by u.device_id;

SQL35 浙大不同难度题目的正确率

用户信息表 user_profile
答题情况明细表 question_practice_detail
题目明细表 question_detail,中question_id是题目编号,difficult_level是题目难度

错误答案示例:

select difficult_level,count(if(result = 'right', 1, 0)) / count(result) as correct_rate
from user_profile u,question_practice_detail t2,question_detail t3
where t1.device_id = t2.device_id and t2.question_id = t3.question_id
and university = '浙江大学'
group by difficult_level
order by correct_rate

if函数汇总第二个返回值设置为0,意图当回答错误时返回0.但此处是计算回答正确题目的总数,当结果不为right时返回0,则此处也有一条会被记数的记录,因此无得到正确的结果.将0改为null,则当result不为right时,不存在会被记数的记录,就能得到正确的结果.
正确答案:

select difficult_level,
count(if(result='right',1,null))/count(q2.question_id)as correct_rate
from question_detail as q1 left join
 question_practice_detail as q2 on q1.question_id=q2.question_id
 left outer join user_profile as u on u.device_id=q2.device_id
 where university='浙江大学' group by difficult_level order by correct_rate

事实上,由于if函数前嵌套了聚集函数,所以当result为right时的返回值可以取不为null的任何数,因为返回值不影响计数.