sql-quick-study
01 基础查询
概念:基础查询
-
题目: 现在运营同学想要用户的设备 id 对应的性别、年龄和学校的数据,请你取出相应数据
语法:
select 要显示的列名 from 表名; SELECT 关键字后给出多个列名,列名之间必须以逗号分隔
SELECT device_id, gender, age, university FROM user_profile;
-
题目: 现在运营想要查看用户信息表中所有的数据,请你取出相应结果
语法:
select * from 表名; 在实际列名的位置使用星号(*)通配符
SELECT * FROM user_profile;
概念:简单处理查询结果
-
题目: 现在运营需要查看用户来自于哪些学校,请从用户信息表中取出学校的去重数据。
语法:
Distinct 关键字加在去重字段前
SELECT DISTINCT university FROM user_profile;
-
题目: 现在运营只需要查看前 2 个用户明细设备 ID 数据,请你从用户信息表 user_profile 中取出相应结果。
语法:
Limit N,N代表想要限制返回的行数
SELECT device_id FROM user_profile LIMIT 2;
-
题目: 现在你需要查看前 2 个用户明细设备 ID 数据,并将列名改为 ‘user_infos_example’,,请你从用户信息表取出相应结果。
语法:
SQL也提供了列重命名的语法--'AS'
SELECT device_id AS user_infos_example FROM user_profile LIMIT 2;
02 条件查询
概念:基础排序
-
题目: 现在运营想要取出用户信息表中的用户年龄,请取出相应数据,并按照年龄升序排序。
语法:
为了明确地排序用 SELECT语句检索出的数据,可使用 ORDER BY 子句。 ORDER BY 子句取一个或多个列的名字,据此对输出进行排序。
SELECT device_id, age FROM user_profile ORDER BY age;
-
题目: 现在运营想要取出用户信息表中的年龄和 gpa 数据,并先按照 gpa 升序排序,再按照年龄升序排序输出,请取出相应数据。
语法:
列名之间用逗号分开
SELECT device_id, gpa, age FROM user_profile ORDER BY gpa, age;
-
题目: 现在运营想要取出用户信息表中对应的数据,并先按照 gpa、年龄降序排序输出,请取出相应数据。
语法:
进行降序排序, 必须指定DESC 关键字
SELECT device_id, gpa, age FROM user_profile ORDER BY gpa DESC, age DESC;
概念:基础操作符
-
题目: 现在运营想要筛选出所有北京大学的学生进行用户调研,请你从用户信息表中取出满足条件的数据,结果返回设备 id 和学校。
语法:
以使用WHERE语句对数据进行过滤
SELECT device_id, university FROM user_profile WHERE university = '北京大学';
-
题目: 现在运营想要针对 24 岁以上的用户开展分析,请你取出满足条件的设备 ID、性别、年龄、学校。
语法:
大于号SQL中的写法为 >
SELECT device_id, gender, age, university FROM user_profile WHERE age > 24;
-
题目: 现在运营想要针对 20 岁及以上且 23 岁及以下的用户开展分析,请你取出满足条件的设备 ID、性别、年龄。
语法:
范围值限制方法为between n1 and n2,n1和n2为要限制的区间范围
使用中需要注意两点:
一是 and 之前的值 需要小于 and 之后的值,不然查询会返回空结果。
二是在 hive sql 中结果会包括两端值,即如果语句写为 betwen 10 and 20, 那么结果中会包括取值等于 10 或 20 的数据。
SELECT device_id, gender, age FROM user_profile WHERE age BETWEEN 20 AND 23;
-
题目: 现在运营想要查看除复旦大学以外的所有用户明细,请你取出相应数据
语法:
不等于号在SQL中的写法为 < > 或 !=,代表筛选出不满足某条件的数据。
SELECT device_id, gender, age, university FROM user_profile WHERE university <> '复旦大学';
-
题目: 现在运营想要对用户的年龄分布开展分析,在分析时想要剔除没有获取到年龄的用户,请你取出所有年龄值不为空的用户的设备 ID,性别,年龄,学校的信息。
语法:
想要剔除空值数据的话,需要用一个特殊的WHERE子句,IS NOT NULL
SELECT device_id, gender, age, university FROM user_profile WHERE age IS NOT NULL;
概念:高级操作符
-
题目: 现在运营想要找到男性且 GPA 在 3.5 以上(不包括 3.5)的用户进行调研,请你取出相关数据。
语法:
在过滤数据时如果我们想结果同时满足多个条件,可以使用 AND 操作符给 WHERE子句附加条件
SELECT device_id, gender, age, university, gpa FROM user_profile WHERE gender = 'male' AND gpa > 3.5;
-
题目: 现在运营想要找到学校为北大或 GPA 在 3.7 以上(不包括 3.7)的用户进行调研,请你取出相关数据
语法:
OR 操作符逻辑与 AND 操作符正好相反,在过滤数据时如果我们想要结果只需满足多个条件中的一个,可以使用OR操作符对条件进行连接
SELECT device_id, gender, age, university, gpa FROM user_profile WHERE university = '北京大学' OR gpa > 3.7;
-
题目: 现在运营想要找到学校为北大、复旦和山大的同学进行调研,请你取出相关数据。
语法:
IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN 取 一组由逗号分隔、括在圆括号中的合法值。
SELECT device_id, gender, age, university, gpa FROM user_profile WHERE university IN ('北京大学', '复旦大学', '山东大学');
-
题目: 现在运营想要找到 gpa 在 3.5 以上(不包括 3.5)的山东大学用户 或 gpa 在 3.8 以上(不包括 3.8)的复旦大学同学进行用户调研,请你取出相应数据
语法:
WHERE 子句其实可以包含任意数目的 AND 和 OR 操作符 | SQL在处理 OR操作符前,优先处理 AND 操作符
SELECT device_id, gender, age, university, gpa FROM user_profile WHERE gpa > 3.5 AND university = '山东大学' OR (gpa > 3.8 AND university = '复旦大学');
-
题目: 现在运营想查看所有大学中带有北京的用户的信息,请你取出相应数据。
语法:
Like操作符——模糊匹配 一般最常用的通配符是 %
SELECT device_id, age, university FROM user_profile WHERE university LIKE '%北京%';
03 高级查询
概念:计算函数
-
题目: 运营想要知道复旦大学学生 gpa 最高值是多少,请你取出相应数据
语法:
MAX()返回指定列中的最大值。MAX在使用时,()需指定要返回最大值的列名
SELECT MAX(gpa) FROM user_profile WHERE university = '复旦大学';
-
题目: 现在运营想要看一下男性用户有多少人以及他们的平均 gpa 是多少,用以辅助设计相关活动,请你取出相应数据。
语法:
COUNT()函数为计数函数,可利用 COUNT()确定表中行的数目或符合特定 条件的行的数目 | AVG()为平均值函数,通过对表中行数计数并计算其列值之和,求得该列的平均值
SELECT COUNT(*) AS male_num, AVG(gpa) FROM user_profile WHERE gender = 'male';
概念:分组查询
-
题目: 现在运营想要对每个学校不同性别的用户活跃情况和发帖数量进行分析,请分别计算出每个学校每种性别的用户数、30 天内平均活跃天数和平均发帖数量。
语法:
用 GROUP BY 分组数据
SELECT gender, university, COUNT(device_id) AS user_num, AVG(active_days_within_30) AS avg_active_day, AVG(question_cnt) AS avg_question_cnt FROM user_profile GROUP BY university, gender;
-
题目: 现在运营想查看每个学校用户的平均发贴和回帖情况,寻找低活跃度学校进行重点运营,请取出平均发贴数低于 5 的学校或平均回帖数小于 20 的学校。
语法:
分组查询的结果不能简单的使用Where语句进行过滤,而需要使用专门的Having语句。
SELECT university, AVG(question_cnt) AS avg_question_cnt, AVG(answer_cnt) AS avg_answer_cnt FROM user_profile GROUP BY university HAVING avg_question_cnt < 5 OR avg_answer_cnt < 20;
-
题目: 现在运营想要查看不同大学的用户平均发帖情况,并期望结果按照平均发帖情况进行升序排列,请你取出相应数据。
语法:
分组查询结果也支持排序功能,所需要用到的语句是Order By
SELECT university, AVG(question_cnt) AS avg_question_cnt FROM user_profile GROUP BY university ORDER BY avg_question_cnt;
04 多表查询
概念:子查询
-
题目: 现在运营想要查看所有来自浙江大学的用户题目回答明细情况,请你取出相应数据
语法:
以 IN 操作符要求的逗号分隔的格式传递给外部查询的 WHERE 子句外部查询
SELECT device_id, question_id, result FROM question_practice_detail WHERE device_id IN ( SELECT device_id FROM user_profile WHERE university = '浙江大学' );
概念:链接查询
-
题目: 运营想要了解每个学校答过题的用户平均答题数量情况,请你取出数据。
问题分解:
限定条件:无;
每个学校:按学校分组,group by university
平均答题数量:在每个学校的分组内,用总答题数量除以总人数即可得到平均答题数量 count(question_id) / count(distinct device_id)。
表连接:学校和答题信息在不同的表,需要做连接
SELECT university, COUNT(question_id) / COUNT(DISTINCT b.device_id) AS avg_answer_cnt FROM ( SELECT device_id, university FROM user_profile )a JOIN ( SELECT device_id, question_id FROM question_practice_detail )b ON a.device_id = b.device_id GROUP BY university;
-
题目: 运营想要计算一些参加了答题的不同学校、不同难度的用户平均答题量,请你写 SQL 取出相应数据
问题分解:
限定条件:无;
不同学校、不同难度:按学校分组按难度分组,GROUP BY university, difficult_level
平均刷题数量:总答题数除以总人数 count(qpd.question_id) / count(distinct qpd.device_id)
需要联表,up 与 qpd 用 device_id 连接,qd 与 qpd 用 question_id 连接。
SELECT university, difficult_level, COUNT(qpd.question_id) / COUNT(DISTINCT qpd.device_id) AS avg_answer_cnt FROM question_practice_detail AS qpd LEFT JOIN user_profile AS up ON up.device_id=qpd.device_id LEFT JOIN question_detail AS qd ON qd.question_id=qpd.question_id GROUP BY university, difficult_level;
-
题目: 运营想要查看参加了答题的山东大学的用户在不同难度下的平均答题题目数,请取出相应数据
问题分解:
限定条件:山东大学;
不同难度:按难度分组,group by difficult_level
平均刷题数量:在每个难度的分组内,用总答题数量除以总人数即可得到平均答题数量 COUNT(qpd.question_id) / COUNT(DISTINCT qpd.device_id)。
表连接:学校和答题信息在不同的表,需要做连接
SELECT up.university, qd.difficult_level, COUNT(qpd.question_id) / COUNT(DISTINCT qpd.device_id) AS avg_answer_cnt FROM question_practice_detail AS qpd LEFT JOIN user_profile AS up ON up.device_id=qpd.device_id LEFT JOIN question_detail AS qd ON qd.question_id = qpd.question_id WHERE up.university = '山东大学' GROUP BY qd.difficult_level;
概念:组合查询
-
题目: 现在运营想要分别查看学校为山东大学或者性别为男性的用户的 device_id、gender、age 和 gpa 数据,请取出相应结果,结果不去重。
语法:
可用 UNION 操作符来组合数条 SQL 查询。利用 UNION,可给出多条 SELECT 语句,将它们的结果组合成一个结果集。| UNION 从查询结果集中自动去除了重复的行;|如果想不去重的返回所有的匹配行,可使用 UNION ALL而不是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';
05 必会的常用函数
概念:条件函数
-
题目: 现在运营想要将用户划分为 25 岁以下和 25 岁及以上两个年龄段,分别查看这两个年龄段用户数量
语法:
Case when
SELECT CASE WHEN age < 25 OR age IS NULL THEN '25岁以下' ELSE '25岁及以上' END age_cut, COUNT(*) number FROM user_profile GROUP BY age_cut;
-
题目: 现在运营想要将用户划分为 20 岁以下,20-24 岁,25 岁及以上三个年龄段,分别查看不同年龄段用户的明细情况,请取出相应数据。(注:若年龄为空请返回其他。)
语法:
Case when
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;
概念:日期函数
-
题目: 现在运营想要计算出 2021 年 8 月每天用户练习题目的数量,请取出相应数据。
语法:
SQL为此提供了对应的年、月、日提取函数,分别为 year(), month(), day()。
SELECT DAY(date) AS day, COUNT(question_id) AS question_cnt FROM question_practice_detail WHERE MONTH(date)=8 AND YEAR(date)=2021 GROUP BY date;
-
题目: 现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。
语法:
语法为date_add(string startdate, interval int day) ,返回开始日期startdate增加days天后的日期
SELECT COUNT(date2) / COUNT(date1) AS avg_ret FROM ( SELECT DISTINCT qpd.device_id, qpd.date AS date1, uniq_date.date AS date2 FROM question_practice_detail AS qpd LEFT JOIN( SELECT DISTINCT device_id, date FROM question_practice_detail )AS uniq_date ON qpd.device_id = uniq_date.device_id AND date_add(qpd.date, interval 1 day)=uniq_date.date )as next_date;
概念:文本函数
-
题目: 现在运营举办了一场比赛,收到了一些参赛申请,表数据记录形式如下所示,现在运营想要统计每个性别的用户分别有多少参赛者,请取出相应结果
语法:
SUBSTRING_INDEX函数用于将字符串依据某个指定分隔符进行切分,并返回指定位置分隔符前的字符。
SELECT SUBSTRING_INDEX(profile, ",", -1) AS gender, COUNT(*) AS number FROM user_submit GROUP BY gender;
-
题目: 现在运营举办了一场比赛,收到了一些参赛申请,表数据记录形式如下所示,现在运营想要统计每个年龄的用户分别有多少参赛者,请取出相应结果
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(profile, ",", 3), ",", -1) AS age, COUNT(*) AS number FROM user_submit GROUP BY age;
-
题目: 对于申请参与比赛的用户,blog_url 字段中 url 字符后的字符串为用户个人博客的用户名,现在运营想要把用户的个人博客用户字段提取出单独记录为一个新的字段,请取出所需数据。
SELECT device_id, SUBSTRING_INDEX(blog_url, "/", -1) AS user_name FROM user_submit;
概念:窗口函数
-
题目: 现在运营想要找到每个学校 gpa 最低的同学来做调研,请你取出每个学校的最低 gpa。
语法:
窗口函数 row_number() over partition by
SELECT device_id, university, gpa FROM ( SELECT *, row_number() over (PARTITION BY university ORDER BY gpa) AS rn FROM user_profile )AS rn_min WHERE rn_min.rn = 1;
06 综合练习
概念:综合练习
-
题目: 现在运营想要了解复旦大学的每个用户在 8 月份练习的总题目数和回答正确的题目数情况,请取出相应明细数据,对于在 8 月份没有练习过的用户,答题数结果返回 0.
问题分解:
限定条件:复旦大学(来自表 user_profile.university),8 月份练习情况(来自表 question_practice_detail.date)
从 date 中取 month:用 month 函数即可;
总题目:count(question_id)
正确的题目数:sum(if(qpd.result=‘right’, 1, 0))
按列聚合:需要输出每个用户的统计结果,因此加上 group by up.device_id
SELECT up.device_id, up.university, COUNT(question_id) AS question_cnt, SUM(IF(qpd.result='right', 1, 0)) AS right_question_cnt FROM user_profile AS up LEFT JOIN question_practice_detail AS qpd ON up.device_id = qpd.device_id AND MONTH(qpd.date) = 8 WHERE up.university = '复旦大学' GROUP BY up.device_id;
-
题目: 现在运营想要了解浙江大学的用户在不同难度题目下答题的正确率情况,请取出相应数据,并按照准确率升序输出。
问题分解:
浙江大学 user_profile.university
正确率:avg(if(qpd.result=‘right’, 1, 0))
并按照准确率升序输出(默认): ORDER BY correct_rate
不同难度题目,加上: GROUP BY difficult_level
SELECT qd.difficult_level, AVG(IF(qpd.result = 'right', 1, 0))AS correct_rate FROM question_practice_detail AS qpd LEFT JOIN user_profile AS up ON up.device_id = qpd.device_id LEFT JOIN question_detail AS qd ON qpd.question_id = qd.question_id WHERE up.university = '浙江大学' GROUP BY difficult_level ORDER BY correct_rate;
-
题目: 现在运营想要了解 2021 年 8 月份所有练习过题目的总用户数和练习过题目的总次数,请取出相应结果
SELECT COUNT(DISTINCT device_id) AS did_cnt, COUNT(*) AS question_cnt FROM question_practice_detail WHERE MONTH(date) = 8 AND YEAR(date) = 2021;