-- 返回第一个不为空的值
select coalesce(NULL,1,2);
-- 替换空值
select nvl(null,0);
-- 拼接字符
select concat(1,2);
select concat_ws(",",1,2)
-- 列转行专用函数
列转行专用函数,有时为了字段拼接效果,多和concat_ws()函数连用,见hive-sql-行列转换
collect_list()函数有序不去重
collect_set()无序去重
--切割字符 返回数组
select split("1,2,3,4,5", ",");
-- 返回两个日期的差值 'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd'
select datediff("2023-02-01","2023-02-01");
-- 返回日期减去天数的日期
select date_sub('2023-02-01',3);
-- 返回日期加上天数的日期
select date_add('2023-02-01',3);
-- 排名函数
row_number() 结果:12345
rank() 结果:12245
dense_rank() 结果:12234
--LAG(col,n,DEFAULT) 返回窗口内往上第n行的值 新增一列
第一个参数为列名,
第二个参数为往上第n行(可选,默认为1),
第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)
--LEAD(col,n,DEFAULT) 返回窗口内往下第n行值
第一个参数为列名,
第二个参数为往下第n行(可选,默认为1),
第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL)
-- 解析复杂数据类型
get_json_object(字段,"$.json_key")--json_key可以使用.追加
-- 返回日期 'yyyy-mm-dd'
select current_date();
-- 返回时间戳 "yyyy-MM-dd HH:mm:ss.ms"
seelct current_timestamp();
-- 返回距离1970年1月1日0点的秒数
select unix_timestamp();
-- 日期转时间戳函数
select unix_timestamp('20220101','yyyymmdd');
select unix_timestamp('20220101 16:34:13.088','yyyymmdd HH:mm:ss.ms')
-- 时间戳转日期函数
select from_unixtime(1641024088,'yyyyMMdd');
select from_unixtime(1641024088,'yyyy-mm-dd HH:mm:ss.ms');
-- 返回年月日时分秒
select year('2022-01-01');
select month('2022-01-01');
select day('2022-01-01');
select hour('2022-01-01 16:34:13.088');
select minute('2022-01-01 16:34:13.088');
select second('2022-01-01 16:34:13.088');
-- 返回月份差值
select months_between('2022-01-01','2023-01-01')
-- 返回以当前日期开始的下一个星期几
星期一:Monday(Mon.)
星期二:Tuesday(Tue.)
星期三:Wednesday(Wed.)
星期四:Thursday(Thu.)
星期五:Friday(Fri.)
星期六:Saturday(Sat.)
星期日:Sunday(Sun.)
select next_day("2022-02-01",'MON')
-- 返回月份相加后的日期
SELECT add_months('2023-01-01',4)
-- 日期转字符串(格式化)函数:date_format
select date_format(current_timestamp(),'yyyy-MM-dd HH:mm:ss');
select date_format(current_date(),'yyyyMMdd');
select date_format('2017-01-01','yyyy-MM-dd HH:mm:ss');
-- yyyymmdd转yyyy-mm-dd 先转时间戳再加杠
select from_unixtime(unix_timestamp('20220101','yyyymmdd'),'yyyy-mm-dd HH:mm:ss.ms');
-- 字符串转时间:to_date() (字符串必须为:yyyy-MM-dd格式)
select to_date('2017-01-01 12:12:12');
-- 类型修改
select cast('112' as int);
select case when 字段 then value else colum end
-- 每一天的用户的留存情况
-- 有一张new_users表记录了每天的新增用户 20200501-20200601 的新增用户
select
user_id,--用户id
dt as new_dt --新增日期
from new_users
where dt >= '2020-05-01' and dt<= '2020-06-01';
--有一张active_users表记录了每天的活跃用户数 20200501-20200601 的活跃用户
select
user_id, --用户id
dt as active_dt, --活跃日期
from active_users
where dt >= '2020-05-01' and dt<= '2020-06-01';
-- 统计当天注册 且 第N日活跃的用户 (t3): 以①为主表 left join ②
select
new_users.new_dt, --用户注册时间
count(distinct t_new.user_id) as cnt_01, --当日注册且当日活跃的用户(当日注册肯定活跃)
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 1,t_new.user_id,null)) as cnt_02,--当日注册 且 第二日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 2,t_new.user_id,null)) as cnt_03,--当日注册 且 第三日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 4,t_new.user_id,null)) as cnt_05,--当日注册 且 第五日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 6,t_new.user_id,null)) as cnt_07,--当日注册 且 第七日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 14,t_new.user_id,null)) as cnt_15,--当日注册 且 第十五日活跃的用户
from new_users
left join
t_active on t_new.user_id = t_active.user_id
group by t_new.new_dt; // t3
select
t.new_dt,--注册时间
t.cnt_01,--当日注册用户
round(cnt_02/ cnt_01 * 100, 2) as keep_02, -- 次日留存
round(cnt_03/ cnt_01 * 100, 2) as keep_03, -- 3日留存
round(cnt_05/ cnt_01 * 100, 2) as keep_05, -- 5日留存
round(cnt_07/ cnt_01 * 100, 2) as keep_07, -- 7日留存
round(cnt_15/ cnt_01 * 100, 2) as keep_15, -- 15日留存
from t3
-- 合并
select
t.new_dt,--注册时间
t.cnt_01,--当日注册用户
round(cnt_02/ cnt_01 * 100, 2) as keep_02, -- 次日留存
round(cnt_03/ cnt_01 * 100, 2) as keep_03, -- 3日留存
round(cnt_05/ cnt_01 * 100, 2) as keep_05, -- 5日留存
round(cnt_07/ cnt_01 * 100, 2) as keep_07, --7日留存
round(cnt_15/ cnt_01 * 100, 2) as keep_15, -- 15日留存
from
(
select
t_new.new_dt, --用户注册时间
count(distinct t_new.user_id) as cnt_01, --当日注册且当日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 1,t_new.user_id,null)) as cnt_02,--当日注册 且 第二日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 2,t_new.user_id,null)) as cnt_03,--当日注册 且 第三日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 4,t_new.user_id,null)) as cnt_05,--当日注册 且 第五日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 6,t_new.user_id,null)) as cnt_07,--当日注册 且 第七日活跃的用户
count(distinct if(datediff(t_active.active_dt,t_new.new_dt) = 14,t_new.user_id,null)) as cnt_15,--当日注册 且 第十五日活跃的用户
from
( -- 新增用户
select
user_id,--用户id
dt as new_dt --新增日期
from new_users
where dt >= '2020-05-01' and dt<= '2020-06-01'
) t_new
left join
( --活跃用户
select
user_id, --用户id
dt as active_dt, --活跃日期
from active_users
where dt >= '2020-05-01' and dt<= '2020-06-01'
)t_active
on t_new.user_id = t_active.user_id
group by t_new.new_dt
)t
create external table lxdl(
user_id string comment '用户id' ,
login_dt string comment '登陆时间'
)
row format delimited fields terminated by ','
1,2022-04-01
1,2022-04-02
1,2022-06-04
2,2022-05-04
2,2022-05-05
2,2022-05-06
3,2022-09-08
-- row_number() + date_sub
-- lead/lag + datediff
-- user_id string comment '用户id'
-- login_dt sting comment '登陆时间'
select
user_id,
min(login_dt) as start_dt,
max(login_dt) as end_dt,
count(1) as continue_dt
from
(
select
user_id,
login_dt,
row_number() over(partition by user_id order by login_dt) as rn -- 每一个用户的每天登录时间
from lxdl
) a group by
user_id,date_sub(login_dt,rn)-- 分组条件是 user_id 和 date_sub(login_dt,rn)
-- 连续登陆,date_sub求出来是相同的
-- 没有第一种直观
with t1 as (select
user_id,
login_dt,
lag(login_dt,1,null) over(partition by user_id order by login_dt) as lag_dt_01,
lead(login_dt,1,null) over(partition by user_id order by login_dt) as lead_dt_01
from lxdl),
t2 AS (
select * from t1 where
(datediff(login_dt,lag_dt_01) = 1 and datediff(lead_dt_01,login_dt) = 1) --连续登录三天
or datediff(login_dt,lag_dt_01) = 1 or datediff(lead_dt_01,login_dt) = 1 -- 连续登录两天
)
SELECT * FROM t2
-- 行转列
《疑犯追踪》,悬疑:动作:科幻:剧情
《Lie to me》,悬疑:警匪,动作:心理:剧情
《战狼 2》,战争:动作:灾难
create external table hlzh(
movie string comment '电影名' ,
style string comment '类型'
)
row format delimited fields terminated by ','
select
movie,
style_name
from hlzh
lateral view explode(split(style,':')) t as style_name
-- 列转行
《008》| 悬疑|
《000》| 动作|
《001》| 科幻|
《002》| 剧情|
《003》| 悬疑|
《004》| 警匪|
《005》| 战争|
《006》| 动作|
《007》| 灾难|
《008》| 科幻|
create external table hlzh1(
movie string comment '电影名',
style string comment '类型'
)
row format delimited fields terminated by '|'
select
style,
concat_ws(',',collect_list(movie)) as movies
from hlzh1
group by style
hive六种面试sql题型