大厂sql题(一):

实现方式sparkSql

 

一、求用户的一个留存数

留存数 =(登录日-注册日 = 流存数)

涉及到求时间的一个差值:

datadiff(from_unixtime(unix_timestamp(login_data,"yyMMdd"),"yy-MM-dd"),from_unixtime(unix_time(register_data,"yyMMdd"),"yy-MM-dd") )

一、unix_timestamp函数用法 1、unix_timestamp() 得到当前时间戳 2、如果参数date满足yyyy-MM-dd HH:mm:ss形式,则可以直接unix_timestamp(string date) 得到参数对应的时间戳 3、如果参数date不满足yyyy-MM-dd HH:mm:ss形式,则我们需要指定date的形式,在进行转换

select unix_timestamp('2009-03-20') --1237507200select unix_timestamp('2009-03-20 00:00:00', 'yyyy-MM-dd HH:mm:ss') --1237507200select unix_timestamp('2009-03-20 00:00:01', 'yyyy-MM-dd HH:mm:ss') --1237507201

二、from_unixtime函数用法 语法:from_unixtime(t1,’yyyy-MM-dd HH:mm:ss’) 其中t1是10位的时间戳值,即1970-1-1至今的秒,而13位的所谓毫秒的是不可以的。 对于13位时间戳,需要截取,然后转换成bigint类型,因为from_unixtime类第一个参数只接受bigint类型。例如:

select from_unixtime(1237507201,'yyyy-MM-dd HH:mm:ss') -- 2009-03-20 00:00:01select from_unixtime(1237507200,'yyyy-MM-dd HH:mm:ss') -- 2009-03-20 00:00:00

常用的插入时间为当前系统时间 转换成距离1970的时间戳,再转换成当前时间

select FROM_UNIXTIME(UNIX_TIMESTAMP() ,'yyyy-MM-dd HH:mm:ss') AS W_INSERT_DT

二、行列变换

方式一:

经典case when item= 'A' then price else 0 end as A(拿一行举例)

然后结果还需要group by分组再做sum聚合或者是其它的聚合

sum(case when item= 'A' then price else 0 end) as A

可能还需要用到cast(xxx,as 转换的类型)

cast(sum(case when item = 'A' then price else 0 end as A)as int)

方式二:

用hive函数来完成

concat(字段,":", 字段):拼接字段

collect_list(): (不去重)

collect_set():(去重)

concat_ws("分隔符",str):

str_to_map(str, "," , ":"):

nvl():判断是否为null,为null,默认给一个值

select usernaem, str_to_map(concat_ws("," , collect_lsit(concat(item,":",price))) , "," , ":") as mp from 某张表 group by username

select username, nul(mp["A"] ,0) as A, nvl( mp["B"] ,0) as B,nvl(mp["C"],0) as C ,nvl(mp["D"],0) as D from 上边的表,————实现了行转列

三、列转行

方式一:

如果是mysql中的话可以用union

select username ,"A" as item , A as price from 某张表 union

select username ,"B" as item , B as price from 某张表 union

select username ,"C" as item , C as price from 某张表 union

select username ,"D" as item , D as price from 某张表

如果是在大数据中的话

方式二:

map(): 往map中添加数据,可以是map("A",A,"B",B) ,按照key:value区分A:A的value

explode():一行变多行,例如username 对应一个map的一个映射

select username ,exploda(map("A",A,"B",B,"C",C,"D",D)) as (item ,price)from 某张表

四、每个小时在线用户数

方式一:

拿两条数据举例,在线的时间有4,5,6,7,8这些小时,然后explode出在线小时的对应的数据,然后分组count就能求出具体某小时在线的用户个数。

1.首先把数据补全,用到开窗函数,

select username, time ,type row_number () over (partition by username order by time ) as rank from 某张表

2.然后做表的错位自连接,用full join,顺便做一下日期的转换

select a.username,replace(repalce(a.time,"T"," 空格"),"00Z","")as a.time,a.type.a.rank,b.username,b.time,.b.type,b.rank from temp1 a full join temp1 b where a.rank = b.rank -1 ;做一个表的错位连接

3.补全数据,前面为空的是login类型,时间是当天的 00:00:00,如果是后一天的数据,类型就是logout,时间是当天的23:59:59。

select

nvl(a.username,b.username) as username1,

nvl(a.time,concat(split(b.time," ")[0],"00:00:00") as time1 #切分完的是一个数组 ,

nvl(a.type,"login" )as type1,

a.rank,

nvl(b.username,a.username) as username2,

nvl(b.time,concat(split(a.time)[0],"23:59:"59) as time2,

nvl(b.type,"logout")as type,

b.rank

from temp1 a full join temp1 b where a.rank = b.rank -1 ;

4.我们要的数据: 前面是login的后面是logot的数据

所以在上面的基础上再加上where条件的过滤,order by username1,time1 asc

5.实现一个udf函数,然后返回一个list(相差的时间点的集合),然后explode形成新的记录。

函数具体是(login的时间,时间差多少个小时) #相差的时间用hour函数

myudf(time1,(hour(time2)-hour(time1)))

// 这里用的scala语言

session.udf.register("myudf",( dt:String , diff:Int )=>{ # 注册用户自定义函数

val returnlist = new ListBuffer()

// 定义需要的类日期格式

val sdf1 = new SimpleDataFormat("yyyy-MM-dd HH:mm:ss")

val sdf2 = new SimpleDataFormat("yyyy-MM-dd_HH")

retunrlsit.append(sdf2.format(sdf1.parse(dt)))

// 循环让日期的天数加1 存到要返回的集合中区

val calendar:Calendar = Calendar.getInstance()

calendar.setTime(sdf1.parse(dt))

for(i <- 0 until diff){

calendar.add(Calendar.HOUR,1) //每循环一次,小时加1

returnlist.append(sdf2.format(calender.getTime))

}

//返回最后的日期集合(实现一对多)

returnlist

})

最后4和5的综合sql:

select username1,time1,type1,username2,time2,type2,explode(myudf(time1,(hour(time2)-hour(time1)))) as rt from temp3 where type1 = 'login' and type2 = 'logout' order by username,time1;

6.最后按照time1分组count即可球的每小时的在线用户个数

select username1 ,count(distinct(username1)) form 某张临时表 group by rt如果数据量很大的话,可以把distinct换成group by username1

1.计算一天里各个用户在线的总时长

用后面的日期减去前面的日期,sum求和即可

2.在线次数

count(*) 一次登入登出算一次在线

3.最大在线时长

登出时间减去登入时间再max()就能求出最大值

五、大数据面试流程及重点需要复习的东西:

首先一定先从项目问起,但是java的一些东西,jvm,GC也会问到

大数据项目中涉及到的几块:

1.ETL的操作

用什么工具抽取的数据?sqoop,flume,DataX,kettle,maxwell等,

2.数据仓库

构建数据仓库用到的,Kafka,HDFS,Hive,知道数据仓库的分层,分多少主题域,做多少指标。还有要知道数据仓库的建模理论

当然数仓中还涉及到一些技术,需要掌握Kylin,Presto,clickhouse,impala等

3.应用的开发(app)

Spark集合,core,sql,Streaming Flink 它们的流式计算,批计算

4.可视化展示

SpringBoot、SSM。小工具superset,sugar等一些BI工具

5.资源调度

yarn,CM平台

6.任务调度

oozie、Azkaban、airflow等

7.数据治理

元数据管理-atlas,数据质量校验,数据安全-Ranger

总结:

数据仓库是重中之重,结合项目去理解去说,其他的每块都需要掌握一些会随着项目一点一点问到,像hdfs,yarn,hive,spark,flink这些都需要知道底层的原理,比如hdfs的读写,mr和yarn的工作流程,hive常用函数,基本语法hsql的使用,以及自定义函数的编写和使用,sparkcore的算子,rdd,以及划分stage等一系列的知识,sparkSql的书写,SparkStreaming批处理的使用等,flink的状态一致性,checkpoint,等原理的东西。其它第三方的工具得明白说得出来它的一个使用,工作机制等。机器学习在大数据的领域一般是做数据分析,这个看自己的能力,说出来肯定是加分项。做过项目的应该都知道离线和实时的区别,所以用到的一些工具,组件与组件之间的联系也要明白

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值