当前位置:   article > 正文

mysql date转string_掌握MySQL!你有多熟练?

mysql cast date string

fab9f29c41db3786ae5b87e3a0df6137.png

学习MySQL也有一阵子,从秦路老师的七周成为数据分析,到《对比EXCEL学习,轻松学习SQL》,再到刷牛客网的SQL题目。总结过SQL要点,也对比EXCLE总结过SQL,但还是觉得不成一体。

aae16e83a0818302072b96a3496dd128.png

所以我想借此文,将自己现在掌握的MySQL一一呈现,也算给自己个交代。

至今学过的知识点:

  1. 表相关(创建,更新,删除表,插入值)
  2. 简单查询(select)
  3. 复杂查询:子查询,多表查询,聚合函数(group by)的使用
  4. 表连接(left/right/inner/outer/cross)
  5. 行转列问题(归根结底case when end的用法)列转行(union)
  6. SQL中常用高级函数相关的题目【case when end】【字符串相关:substr/concat/split】
  7. 基础进阶【日期函数】【组内排序:row_number()/rank()/dense_rank()】【取百分比】【窗口函数】 Reference: 无眠:数据分析面试必备——SQL你准备好了吗?
  8. 运营数据分析:复购率、回购率
  9. DAU的分析,次日留存、三日留存、七日留存,及留存率

不熟悉的SQL函数

1)取百分比可以用【percentile】

但不知为何我的电脑里不存在percentile,用法记录在此

  1. #想要获取top10%的值?—— percentile 百分位函数
  2. -- 获取income字段的top10%的阈值
  3. select percentile(CAST (salary AS int),0.9)) as income_top10p_threshold from table_1;
  4. -- 获取income字段的10个百分位点
  5. select percentile(CAST (salary AS int),array(0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0)) as income_percentiles
  6. from table_1;
  7. #CAST它常用于string/int/double型的转换。

查找前20%的数据,我用以下方法

【解题思路】①用row_rumber()对数据进行降序排名,得到ranking ②ranking<=(select max(ranking) from 表)

#查找前20%数据(拼多多面试题)

用户访问次数表,列名包括用户编号、用户类型、访问量。要求在剔除访问次数前20%的用户后,每类用户的平均访问次数。

ac34acabc316219faccb73f2edc133d7.png
  1. SELECT t.用户类型,avg(t.访问量) from
  2. (SELECT *,row_number() over (ORDER BY 访问量 desc) as ranking from 拼多多访问) t
  3. where t.ranking>(SELECT count(用户编号) from 拼多多访问)*0.2
  4. GROUP BY t.用户类型;

2)字符串相关

  • substr/concat/split
  1. concat( A, B...)返回将A和B按顺序连接在一起的字符串,如:concat('foo', 'bar') 返回'foobar'
  1. select concat('www','.iteblog','.com') from
  2. iteblog;
  3. --得到 www.iteblog.com
  4. #变形①--以分隔符连接
  5. SELECT CONCAT_WS(',','GOOD','JOB')
  6. ---得到GOOD,JOB
  7. #变形②--同组连接
  8. select dept_no,group_concat(emp_no) as employees from dept_emp
  9. group by dept_no
  10. ;
  11. --将表dept_emp中相同dept_no的emp_no连接(from牛客网53题)

2. split(str, regex)用于将string类型数据按regex提取,分隔后转换为array。???

  1. -- 以","为分隔符分割字符串,并转化为array
  2. Select split("1,2,3",",")as value_array from table_1;
  3. -- 结合array index,将原始字符串分割为3
  4. select value_array[0],value_array[1],value_array[2] from
  5. (select split("1,2,3",",")as value_array from table_1 )t

3. substr(str,0,len) 截取字符串从0位开始的长度为len个字符。

  1. select substr('abcde',3,2) from
  2. iteblog;
  3. -- 得到cd
  • 字符串长度/替换

查找字符串'10,好,B' 中逗号','出现的次数cnt(第51题)

  1. #总长度-剔除(,)长度
  2. #剔除(,)用replace
  3. SELECT CHAR_LENGTH('10,好,B')-CHARACTER_LENGTH(replace('10,好,B',',',''))

注意:char_length()基于字符计数,length()基于字节计数

  1. SELECT replace('10,好,B',',',''),
  2. CHAR_LENGTH('10,好,B'),
  3. CHARACTER_LENGTH(replace('10,好,B',',','')),
  4. length('10,好,B'),
  5. length(replace('10,好,B',',',''))

8c71f880f5a7f7c54600051d29095010.png

以下是各种练习

这部分,是我的错题本,会随刷题不断增加内容~

1)基础过关50题

猴子:图解SQL面试题:经典50题,题目很基础,适合初学练手~

2)牛客网题目

  • 复杂查询——【牛客网28题】查找描述信息(film.description)中包含robot的电影对应的分类名称(category.name)以及电影数目(count(film.film_id)),而且还需要该分类包含电影总数量(count(film_category.category_id))>=5部

1850e35101352e81b7c2ba464829ea43.png
  1. 【思路拆解】
  2. Step1:明确最终输出:包含robot的电影【分类名称】以及对应分类的电影【数目】
  3. Step2:明确限制条件
  4. ①film.description包含robot(like '%robot%')
  5. ②查找出category_id,满足(count(film_category.category_id))>=5
  6. 【解答】
  7. SELECT c.`name`,count(f.film_id) from film f
  8. LEFT JOIN film_category fc
  9. on f.film_id=fc.film_id
  10. LEFT JOIN category c
  11. on c.category_id=fc.category_id
  12. where f.description like '%robot%'
  13. and fc.category_id=(
  14. select category_id from film_category
  15. group by category_id
  16. having count(film_id)>=5);
  • 考虑重复值1——【牛客网8题】找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
  1. 【已知】
  2. CREATE TABLE `salaries` (
  3. `emp_no` int(11) NOT NULL,
  4. `salary` int(11) NOT NULL,
  5. `from_date` date NOT NULL,
  6. `to_date` date NOT NULL,
  7. PRIMARY KEY (`emp_no`,`from_date`));
  8. 【思路一】用distinct去重
  9. select distinct(salary) from salaries
  10. where to_date='9999-01-01'
  11. order by salary desc;
  12. 【思路二】用group by
  13. select salary from salaries
  14. where to_date='9999-01-01'
  15. group by salary
  16. order by salary desc;

考虑重复值2——【牛客网第14题】从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。注意对于重复的emp_no进行忽略(即emp_no重复的title不计算,title对应的数目t不增加)。

  1. 【已知】
  2. CREATE TABLE IF NOT EXISTS `titles` (
  3. `emp_no` int(11) NOT NULL,
  4. `title` varchar(50) NOT NULL,
  5. `from_date` date NOT NULL,
  6. `to_date` date DEFAULT NULL);
  7. 【求解】
  8. select title,count(distinct emp_no) as t from titles
  9. group by title
  10. having count(distinct emp_no)>=2
  11. ;
  • 多思维解题——【牛客网第17题】获取当前(to_date='9999-01-01')薪水第二多的员工的emp_no以及其对应的薪水
  1. 【已知】
  2. CREATE TABLE `salaries` (
  3. `emp_no` int(11) NOT NULL,
  4. `salary` int(11) NOT NULL,
  5. `from_date` date NOT NULL,
  6. `to_date` date NOT NULL,
  7. PRIMARY KEY (`emp_no`,`from_date`));
  8. 【思路1】用limit函数来限制
  9. select emp_no,salary from salaries
  10. order by salary desc
  11. limit 1,1
  12. 【思路3】第二大就是比最大小的最大
  13. select emp_no,max(salary)
  14. from salaries
  15. where salary < (select max(salary) from salaries)
  16. 【思路2】用窗口函数排序
  17. select t.emp_no,t.salary from
  18. (select *,row_number() over (order by salary desc) as ranking from salaries) t
  19. where t.ranking=2
  20. ;

3)连续签到天数

求解连续签到问题的关键在于找出数据间的逻辑关系,连续签到意味着某两列数据之差是一致的。

腾讯经典面试题,百度也考过☞接受挑战

数据分析SQL面试9套题里第8题也出现了连续签到,一个表记录了某论坛会员的发贴情况,存储了user_id ,发贴时间post_time和内容content。找出连续发贴三次及以上的会员。

98e53c2dc7bfb910a126326ee8a4a2b3.png
思路:①每个用户按照签到先后排序 ②所有用户按照签到先后排序 ③如果连续签到,则排序②与排序①的差值相同
  1. SELECT t.user_id from
  2. (SELECT user_id,post_time,
  3. ROW_number() over (PARTITION by user_id ORDER BY post_time) as row1,
  4. row_number() over (order by post_time) as row2,
  5. row_number() over (order by post_time)-ROW_number() over (PARTITION by user_id ORDER BY post_time) as diff
  6. from tablename)t
  7. GROUP BY t.user_id,t.diff
  8. having count(t.user_id)>=3
  9. ;

4)数据分析SQL面试题9套汇总

参考:数据蛙datafrog:数据分析SQL面试题目9套汇总,此外在B站关注同名账号,也有不少资料的~

  1. 字符串连接
  2. 留存率
  3. 行列转换
  4. 列转行
  5. 窗口函数应用(求累计和)
  6. 查询登录次数
  7. 红包领取活动
  8. 连续签到
  • 【题目】求用户号对应的前两个不同场景(场景重复的话,选重复场景的第一个访问时间,场景不足两个的输出为止)

adada3a187623570025bf308854651de.png
该题目与牛客网第53题类似,涉及字符串连接的知识:可以用group_concat(列名 SEPARATOR '分隔符') 解决。解题思路 ①排序 ②条件查询 ③concat函数连接
  1. SELECT concat(t.user_id,'-',GROUP_CONCAT(DISTINCT t.scene SEPARATOR '-') ) as reasult FROM
  2. (SELECT *,
  3. row_number() over (PARTITION by user_id order by time) as ranking
  4. from scene) t
  5. where t.ranking<3
  6. GROUP BY t.user_id
  7. ;
  • 【题目】求累计和(窗口函数之聚合函数,如sum. avg, count, max, min等的应用)

8f6ffef224063304c72e73fe71c5196e.png
  1. SELECT t.year,t.month,t.value,sum(value) over (PARTITION by year order by t.month) as ysum,
  2. sum(value) over (order by t.ranking) as sum
  3. FROM
  4. (SELECT year(fdate) as year,
  5. month(fdate) as month,
  6. row_number() over (order by fdate) as ranking,
  7. sum(value) as value
  8. from sales
  9. group by year(fdate),month(fdate))t;

【题目】生成登录表,求出最近一次登录时间以及每个用户登录总次数(当天登录多次记录1次)

注意时间函数的用法。①文本转换成时间 DATE_FORMAT(文本,'%Y-%m-%d %H:%i:%s') ②时间的提取,datetime转化成date格式,直接用date()

80aa5ae51b366ea15406f01af1f70677.png
  1. 【生成表】
  2. create table userlog
  3. (
  4. id int ,
  5. name varchar(10),
  6. EmailAddress varchar(50),
  7. lastlogon varchar(50)
  8. );
  9. insert into userlog values(100,'test4','test4@yahoo.cn','2007-11-25 16:31:26');
  10. insert into userlog values(13,'test1','test4@yahoo.cn','2007-3-22 16:27:07');
  11. insert into userlog values(19,'test1','test4@yahoo.cn','2007-10-25 14:13:46');
  12. insert into userlog values(42,'test1','test4@yahoo.cn','2007-10-25 14:20:10');
  13. insert into userlog values(45,'test2','test4@yahoo.cn','2007-4-25 14:17:39');
  14. insert into userlog values(49,'test2','test4@yahoo.cn','2007-5-25 14:22:36');
  15. UPDATE userlog set lastlogon=DATE_FORMAT(lastlogon,'%Y-%m-%d %H:%i:%s');
  16. SELECT * from userlog;
  17. 【查询登录次数】
  18. SELECT name,max(lastlogon) as 最近一次登录时间,
  19. count(DISTINCT date(lastlogon)) as 登录次数 from userlog
  20. group by name;

【题目】红包领取

两张表如下

ff2cd1882d7e2eb202d0ef087fd8c55f.png

1、计算2019年6月1日至今,每日DAU(活跃用户量,即有登陆的用户)
2、计算20190601至今,每日领取红包的新用户数,老用户数,及人均领取金额,人均领取次数(注意领取人数中有未登录用户)
3、计算2019年3月,每个月按领红包取天数为1、2、3……30、31天区分,计算取每个月领取红包的用户数,人均领取金额,人均领取次数
4、计算2019年3月,每个月领过红包用户和未领红包用户的数量
5、计算2019年3月至今,每个月活跃用户的注册日期,2019年3月1日前注册的用户日期填空即可
6、计算2019年3月至今,每日的用户次日留存率,领取红包用户的次日留存,未领取红包用户的次日留存率
7、计算2019年6月1日至今,每日新用户领取得第一个红包的金额
8、计算2019年3月1日至今,每个新用户领取的第一个红包和第二个红包的时间差(只计算注册当日有领取红包的用户,注册当日及以后的DAU表中新用户为1的用户)

  1. 1】每日DUA人数
  2. SELECT `登录日期`,count(`用户ID`) as DAU from 活跃用户表
  3. where `登录日期`>20190531
  4. GROUP BY `登录日期`;

6a34ad894fe6cec4dfceffb086088977.png
  1. 2】每日领取红包人员构成(表连接的时候不仅要id连接,还要时间连接)
  2. SELECT p.`抢红包日期`,
  3. count(DISTINCT case when u.`是新用户`='1' then p.`用户ID` else null end) as 新用户数,
  4. count(DISTINCT case when u.`是新用户`='0' then p.`用户ID` else null end) as 老用户数,
  5. count(DISTINCT case when u.`是新用户`is null then p.`用户ID` else null end) as 未登录用户数,
  6. round(sum(p.`金额`)/count(DISTINCT p.`用户ID`),2) as 人均领取金额,
  7. count(p.`用户ID`)/count(DISTINCT p.`用户ID`) as 人均领取次数
  8. from `领取红包表` p
  9. LEFT JOIN `活跃用户表` u
  10. on p.`用户ID`=u.`用户ID` and p.`抢红包日期`=u.`登录日期`
  11. where p.`抢红包日期`>20190531
  12. GROUP BY p.`抢红包日期`
  13. ;

2c89246b29adc0050ff29eab0461a499.png
  1. 3】每月领取红包状况~这个很简单
  2. SELECT DATE_FORMAT(`抢红包日期`,'%Y-%m') as 月份,
  3. count(DISTINCT `抢红包日期`) as 领取天数,
  4. count(DISTINCT `用户ID`) as 每个月领取红包人数,
  5. sum(`金额`)/count(DISTINCT `用户ID`) as 人均领取金额,
  6. count(`用户ID`)/count(DISTINCT `用户ID`) as 人均领取次数
  7. from `领取红包表`
  8. GROUP BY DATE_FORMAT(`抢红包日期`,'%Y-%m');

937a988e6787532935f41dc3c5f310ef.png
  1. 4】登录用户中,每月领取红包人数 和 未领取红包人数
  2. SELECT DATE_FORMAT(u.`登录日期`,'%Y-%m') as 月份,
  3. count(DISTINCT case when p.`用户ID` is not null then u.`用户ID` else null end)as 领红包人数,
  4. count(DISTINCT case when p.`用户ID` is null then u.`用户ID` else null end)as 未领红包人数
  5. from `活跃用户表` u
  6. LEFT JOIN `领取红包表` p
  7. on u.`用户ID`=p.`用户ID` and u.`登录日期`=p.`抢红包日期`
  8. group by DATE_FORMAT(u.`登录日期`,'%Y-%m')
  9. ;

44442396fc9fdad37f57de5226a75dc1.png
  1. 5】各用户首次登录的日期
  2. SELECT t1.`用户ID`,t2.`登录日期` as 注册日期 FROM
  3. (SELECT `用户ID` from `活跃用户表`
  4. group by `用户ID`)t1
  5. LEFT JOIN
  6. (SELECT * from `活跃用户表`
  7. where `是新用户`=1)t2
  8. on t1.`用户ID`=t2.`用户ID`
  9. ;

925b063da50f92468f4e8e13a0a9ad73.png
【6】解题思路是将要的总结果拆分,再将一个个分结果连接。
①求出登录用户次日留存率,活跃用户表与活跃用户表连接
②当日领取红包占比,活跃用户表与领取红包表连接
③领取红包次日留存,领取红包表与活跃用户表连接
以上三个连接均为左连接
  1. 6】每日登录用户的次日留存、领取红包用户的次日留存、未领取红包用户的次日留存
  2. SELECT t1.`登录日期`,t1.`当日登录人数`,t2.`领取红包数`,t2.`当日领取红包占比`,t1.`用户次日留存率`,t3.`当日领红包次日留存率` from
  3. (SELECT a.`登录日期`,
  4. count(DISTINCT a.`用户ID`) 当日登录人数,
  5. count(case when DATE_ADD(a.`登录日期`,INTERVAL 1 day)=b.`登录日期` then b.`用户ID` else null end) as 次日登录人数,
  6. count(case when DATE_ADD(a.`登录日期`,INTERVAL 1 day)=b.`登录日期` then b.`用户ID` else null end)/count(DISTINCT a.`用户ID`) as 用户次日留存率
  7. from `活跃用户表` a
  8. LEFT JOIN `活跃用户表` b
  9. on a.`用户ID`=b.`用户ID`
  10. GROUP BY a.`登录日期`) t1
  11. JOIN
  12. (SELECT u.`登录日期`,count(DISTINCT u.`用户ID`) as 当日登录数,
  13. count(DISTINCT p.`用户ID`)as 领取红包数,
  14. count(DISTINCT p.`用户ID`)/count(DISTINCT u.`用户ID`) as 当日领取红包占比
  15. from `活跃用户表` u
  16. LEFT JOIN `领取红包表` p
  17. on u.`用户ID`=p.`用户ID` and u.`登录日期`=p.`抢红包日期`
  18. group by u.`登录日期`)t2
  19. on t1.`登录日期`=t2.`登录日期`
  20. JOIN
  21. (SELECT p1.`抢红包日期`,
  22. count(DISTINCT p1.`用户ID`) as 当日抢红包人数,
  23. count(DISTINCT case when DATE_ADD(p1.`抢红包日期`,INTERVAL 1 day)=u1.`登录日期` then u1.`用户ID` else null end) as 领红包次日登录人数,
  24. count(DISTINCT case when DATE_ADD(p1.`抢红包日期`,INTERVAL 1 day)=u1.`登录日期` then u1.`用户ID` else null end)/count(DISTINCT p1.`用户ID`) as 当日领红包次日留存率
  25. from `领取红包表` p1
  26. LEFT JOIN `活跃用户表` u1
  27. on p1.`用户ID`=u1.`用户ID`
  28. group by p1.`抢红包日期`)t3
  29. on t2.`登录日期`=t3.抢红包日期
  30. ;

ca54377f39f210f4cd02f6958cb27201.png
【7】思路:①筛选出每个用户首次抢红包的时间 ②筛选出首次抢的红包金额 ③活跃用户表与筛选出的表连接,求出结果
  1. SELECT t1.`登录日期` as 日期,t1.`用户ID`,t2.`金额` FROM
  2. (SELECT `登录日期`,用户ID from `活跃用户表`
  3. where `登录日期`>=20190601 and `是新用户`=1)t1
  4. LEFT JOIN
  5. (SELECT t.`用户ID`,p.`抢红包日期`,p.`金额` from
  6. (SELECT `用户ID`,min(`抢红包时间`) as 第一次领取时间 from `领取红包表`
  7. GROUP BY `用户ID`)t
  8. JOIN `领取红包表` p
  9. on t.`用户ID`=p.`用户ID` and t.`第一次领取时间`=p.`抢红包时间`) t2
  10. on t1.`用户ID`=t2.`用户ID` and t1.`登录日期`=t2.`抢红包日期`
  11. ;

d0e535315cc67beb7514c47d63130861.png
【8】思路:①求出新用户首次抢红包时间,活跃用户表left join领取红包表,使用筛选条件,并对连接表以领取红包userid进行分组,找出组内最早时间,即为首次领取红包时间。②将表一与领取红包表再次连接,并筛选出抢红包时间一致的数据,用TIMESTAMPDIFF求出时间间隔
  1. SELECT t1.`用户ID`,t1.`首次抢红包时间`,
  2. min(TIMESTAMPDIFF(minute,t1.`首次抢红包时间`,t2.`抢红包时间`)) as 抢红包时间间隔
  3. FROM
  4. (SELECT p.`用户ID`,min(p.`抢红包时间`) as 首次抢红包时间 from `活跃用户表` u
  5. LEFT JOIN `领取红包表` p
  6. on u.`用户ID`=p.`用户ID` and u.`登录日期`=p.`抢红包日期`
  7. where u.`是新用户`='1'
  8. GROUP BY p.`用户ID`) t1
  9. LEFT JOIN `领取红包表` t2
  10. ON t1.`用户ID`=t2.`用户ID`
  11. where t1.`首次抢红包时间`!=t2.`抢红包时间`
  12. group by t1.`用户ID`;
  13. #窗口函数来排序求解
  14. SELECT t1.用户ID,timeDIFF(t2.抢红包时间,t1.抢红包时间) from
  15. (SELECT * FROM
  16. (SELECT `抢红包时间`,`用户ID`,row_number() over (PARTITION by `用户ID` ORDER BY `抢红包时间`) as ranking from `领取红包表`
  17. WHERE `用户ID` in
  18. (SELECT `用户ID` from `活跃用户表`
  19. where `是新用户`=1)) t
  20. where t.ranking=1) t1
  21. LEFT JOIN
  22. (SELECT * FROM
  23. (SELECT `抢红包时间`,`用户ID`,row_number() over (PARTITION by `用户ID` ORDER BY `抢红包时间`) as ranking from `领取红包表`
  24. WHERE `用户ID` in
  25. (SELECT `用户ID` from `活跃用户表`
  26. where `是新用户`=1)) t
  27. where t.ranking=2) t2
  28. on t1.用户ID=t2.用户ID
  29. ;

cd0d3247d0faeea6a9f1f9785299f999.png

这个内容实在是太多了,慢慢刷~数据分析真题日刷 | 目录索引_是圣洁呀✨-CSDN博客

(~ ̄▽ ̄)~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/397781
推荐阅读
相关标签
  

闽ICP备14008679号