HIVE SQL日常使用记录

目录

使用记录

行专列

列转行

过滤含数字/含汉字

HIVE计算时长(过滤不闭合时间段)

案例描述

时长计算

日期格式转换

动态分区&静态分区

shell中的for循环


目录

使用记录

行专列

数据、建表如下:
孙悟空 白羊座 A
大海 射手座 A
宋宋 白羊座 B
猪八戒 白羊座 A
凤姐 射手座 A
小明 白羊座 B

需求如下:
把星座和血型一样的人归类到一起

射手座,A 大海|凤姐
白羊座,A 孙悟空|猪八戒
白羊座,B 宋宋|小明

分析:

  • 先用concat_ws函数将将星座和血型用“,”连接
  • 在根据连接好的星座和血型group by
  • 用collect_set函数对name聚合,
  • 用concat_ws函数对聚合后的name用“|”分割

实现如下:

SELECT
t1.c_b,
CONCAT_WS("|",collect_set(t1.name))
FROM (
SELECT
NAME,
CONCAT_WS(',',constellation,blood_type) c_b
FROM person_info
)t1
GROUP BY t1.c_b

列转行

数据如下:
《疑犯追踪》 悬疑,动作,科幻,剧情
《Lie to me》 悬疑,警匪,动作,心理,剧情
《战狼 2》 战争,动作,灾难

需求如下:
将电影分类中的数组数据展开

《疑犯追踪》 悬疑
《疑犯追踪》 动作
《疑犯追踪》 科幻
《疑犯追踪》 剧情
《Lie to me》 悬疑
《Lie to me》 警匪
《Lie to me》 动作
《Lie to me》 心理
《Lie to me》 剧情
《战狼 2》 战争
《战狼 2》 动作
《战狼 2》 灾难

分析:

先用split函数将category根据“,”分割成数组
lateral view结合explode函数进行炸裂后的侧写
实现如下:

SELECT
movie,
category_name
FROM
movie_info
lateral VIEW
explode(split(category,",")) movie_info_tmp AS category_name;

我的实现

--get_json_all_keys为自定义UDF函数,获得json所有key,按','分割
SELECT u_id,u_tag FROM ods_user_action_score 
lateral VIEW
explode(split(get_json_all_keys(action_data),',')) u_tag_tmp AS u_tag
where action_data is NOT NULL and action_data <>'[]' and action_data <> '';

过滤含数字/含汉字

--含汉字 rlike '[\\u4e00-\\u9fa5]'
--含数字 rlike '[0-9]'
select u_tag, u_id from dws_user_tags
where u1.u_tag rlike '[\\u4e00-\\u9fa5]' or u1.u_tag rlike '[0-9]' 

HIVE计算时长(过滤不闭合时间段)

lead( date_time, 1, null ) over ( PARTITION BY user_id ORDER BY date_time ) 

lag( xxx, xxx, xxx) over ( PARTITION BY xxx ORDER BY xxx) 

Hive的分析函数又叫窗口函数,在oracle中就有这样的分析函数,主要用来做数据统计分析的。
Lag和Lead分析函数可以在同一次查询中取出同一字段的前N行的数据(Lag)和后N行的数据(Lead)作为独立的列。这种操作可以 代替表的自联接,并且LAG和LEAD有更高的效率,其中over()表示当前查询的结果集对象,括号里面的语句则表示对这个结果集进行处理。

案例描述

用户行为分析,分析用户在线时长或者浏览时长等数据。过滤掉不闭合的时间段

数据结构

id  user type       time
1	101	quit_time	2021-11-01 10:34:08
2	101	landing_time	2021-11-01 10:34:14
3	101	quit_time	2021-11-01 10:34:21
4	101	landing_time	2021-11-01 10:34:25
5	101	quit_time	2021-11-01 10:39:14
6	101	landing_time	2021-11-01 10:47:34
7	101	quit_time	2021-11-01 10:48:05
8	101	landing_time	2021-11-01 14:19:09
9	101	quit_time	2021-11-01 14:20:28
10	101	landing_time	2021-11-01 14:36:30
11	101	quit_time	2021-11-01 14:41:38
12	101	landing_time	2021-11-01 14:55:41
13	123062	landing_time	2021-11-01 10:07:07
14	123062	landing_time	2021-11-01 10:20:20
15	123062	landing_time	2021-11-01 15:06:10
16	123062	landing_time	2021-11-01 15:08:48
17	123062	landing_time	2021-11-01 15:21:57
18	123062	landing_time	2021-11-01 15:41:01
19	123062	landing_time	2021-11-01 16:37:50
20	123062	landing_time	2021-11-01 16:50:47
21	123062	landing_time	2021-11-01 17:11:37
22	123491	landing_time	2021-11-01 21:52:57
23	123491	quit_time	2021-11-01 21:52:59
24	123511	landing_time	2021-11-01 17:03:25
25	123511	quit_time	2021-11-01 17:04:38
26	123511	landing_time	2021-11-01 17:04:40
27	123511	quit_time	2021-11-01 17:05:27
28	123511	landing_time	2021-11-01 17:20:51

需求是算出每个用户在线时长,过滤掉不闭合的时间段。

使用lead over (partition by order by)窗口函数,lead( date_time, 1, null ) over ( PARTITION BY user_id ORDER BY date_time ) 意思是下一条记录的时间作为结束时间;

case when 中的and (    lead( behavior_type, 1, null ) over ( PARTITION BY user_id ORDER BY date_time )) = 'quit_time'意思是下一条是登出类型的数据时,过滤掉不闭合的时间段。

SELECT
date_id,
user_id,
CASE WHEN behavior_type = 'quit_time' THEN logout_ts ELSE login_ts END AS login_ts,
CASE WHEN behavior_type = 'quit_time' THEN login_ts ELSE logout_ts END AS logout_ts 
FROM(
	SELECT date_id,user_id,date_time AS login_ts,logout_ts,rn,behavior_type 
	FROM(
SELECT
		date_id,behavior_type,user_id,date_time,
		CASE 
		  WHEN behavior_type = 'landing_time' 
		    and (lead( behavior_type, 1, null ) over ( PARTITION BY user_id ORDER BY date_time )) = 'quit_time'
		  THEN
		   lead( date_time, 1, null ) over ( PARTITION BY user_id ORDER BY date_time ) 
		  ELSE null
		END AS logout_ts,
		ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY date_time ASC ) rn 
		FROM dws_base_event_user 
		WHERE dt = '${do_date}' and user_id <> '0' and (behavior_type = 'landing_time' OR behavior_type = 'quit_time' )
	) tt 
WHERE behavior_type = 'landing_time' OR ( behavior_type = 'quit_time' AND rn = 1 ) ) ttt;

结果如下

id  date       user  login_ts  logout_ts 
1	20211101	101	NULL	2021-11-01 10:34:08
2	20211101	101	2021-11-01 10:34:14	2021-11-01 10:34:21
3	20211101	101	2021-11-01 10:34:25	2021-11-01 10:39:14
4	20211101	101	2021-11-01 10:47:34	2021-11-01 10:48:05
5	20211101	101	2021-11-01 14:19:09	2021-11-01 14:20:28
6	20211101	101	2021-11-01 14:36:30	2021-11-01 14:41:38
7	20211101	101	2021-11-01 14:55:41	NULL
8	20211101	123062	2021-11-01 10:07:07	NULL
9	20211101	123062	2021-11-01 10:20:20	NULL
10	20211101	123062	2021-11-01 15:06:10	NULL
11	20211101	123062	2021-11-01 15:08:48	NULL
12	20211101	123062	2021-11-01 15:21:57	NULL
13	20211101	123062	2021-11-01 15:41:01	NULL
14	20211101	123062	2021-11-01 16:37:50	NULL
15	20211101	123062	2021-11-01 16:50:47	NULL
16	20211101	123062	2021-11-01 17:11:37	NULL
17	20211101	123491	2021-11-01 21:52:57	2021-11-01 21:52:59
18	20211101	123511	2021-11-01 17:03:25	2021-11-01 17:04:38
19	20211101	123511	2021-11-01 17:04:40	2021-11-01 17:05:27
20	20211101	123511	2021-11-01 17:20:51	NULL

得到此记录后,只需按NULL过滤掉不闭合的时间段,计算时长即可

时长计算

unix_timestamp()是hive系统时间,格式是timestamp,精确到秒。
   unix_timestamp(ymdhms)是把时间转换成timestamp格式,是2018-05-23 07:15:50格式。
   unix_timestamp() - unix_timestamp(ymdhms)是两个时间转换为timestamp之后相减,timestamp单位是秒,相减之后是两个时间之间相差的秒数。
   CAST((unix_timestamp() - unix_timestamp(ymdhms)) % 60 AS int)是相差的秒数。
   CAST((unix_timestamp() - unix_timestamp(ymdhms)) / 60 AS int) % 60是相差的分钟数。
   CAST((unix_timestamp() - unix_timestamp(ymdhms)) / (60 * 60) AS int) % 24是相差的小时数。
   concat(CAST((unix_timestamp() - unix_timestamp(ymdhms)) / (60 * 60 * 24) AS int)是相差的天

日期格式转换

方法1: from_unixtime+ unix_timestamp
 
--20171205转成2017-12-05 
select from_unixtime(unix_timestamp('20171205','yyyyMMdd'),'yyyy-MM-dd') ;
 
--2017-12-05转成20171205
select from_unixtime(unix_timestamp('2017-12-05','yyyy-MM-dd'),'yyyyMMdd') ;

--2017-12-05转成20171205
select date_formate('2017-12-05','yyyyMMdd') ;

--日期间隔天数 日期格式必须是yyyy-MM-dd
SELECT datediff('2021-07-25', '2021-07-01');

动态分区&静态分区


INSERT OVERWRITE TABLE dwt_user_measure_topic PARTITION(dt,measure='UB005_') 
select
  u.date_id, 
  'UB004' measure_id, 
  u.count_num measure_value, 
  cast(u.parent_app_id as STRING) parent_app_id, 
  null province,
  null city,
  null measure_hour,
  null extend,
  '注册用户日活跃量' remark, 
  date_format(current_timestamp, 'yyyyMMddHHmmss') etl_stamp ,
  from_unixtime(unix_timestamp(u.date_id,'yyyymmdd'),'yyyy-mm-dd') dt
from 
  (SELECT 
      count(DISTINCT(case when u1.is_visitor='0' then u1.user_id else null end)) count_num, 
      u2.parent_id parent_app_id,u1.date_id
    from 
      dws_base_event_user u1 
      LEFT JOIN ods_app_config u2 on u1.app_id = u2.app_id 
    GROUP BY u2.parent_id,u1.date_id) u

hive报错

FAILED: SemanticException [Error 10094]: Line 4:56 Dynamic partition cannot be the parent of a static partition ''UB005_''

注意,动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区

修改为

INSERT OVERWRITE TABLE dwt_user_measure_topic PARTITION(dt,measure) 
select
  u.date_id, 
  'UB004' measure_id, 
  u.count_num measure_value, 
  cast(u.parent_app_id as STRING) parent_app_id, 
  null province,
  null city,
  null measure_hour,
  null extend,
  '注册用户日活跃量' remark, 
  date_format(current_timestamp, 'yyyyMMddHHmmss') etl_stamp ,
  from_unixtime(unix_timestamp(u.date_id,'yyyymmdd'),'yyyy-mm-dd') dt,
  'UB005_' measure
from 
  (SELECT 
      count(DISTINCT(case when u1.is_visitor='0' then u1.user_id else null end)) count_num, 
      u2.parent_id parent_app_id,u1.date_id
    from 
      dws_base_event_user u1 
      LEFT JOIN ods_app_config u2 on u1.app_id = u2.app_id 
    GROUP BY u2.parent_id,u1.date_id) u

shell中的for循环

#$1和$2为hue 的workflow传参
first=$1
second=$2

while [ "$first" != "$second" ]
do
echo $first

sql_topic="
use dd_database_bigdata;
--DWT层 用户活跃主题表
insert overwrite table dwt_user_active_topic
select 
	nvl (new.user_id, old.user_id) user_id,
	nvl (new.parent_app_id, old.parent_app_id) parent_app_id,
	IF (old.user_id IS NULL,new.mobile_type,old.mobile_type_first) mobile_type_first,
	IF (old.user_id IS NULL,new.province,old.province_first) province_first,
	IF (old.user_id IS NULL,new.city,old.city_first) city_first,
	IF (old.login_date_first IS NULL,'$first',old.login_date_first) login_date_first,
	IF (new.user_id IS NOT NULL,from_unixtime(unix_timestamp(new.date_id,'yyyymmdd'),'yyyy-mm-dd'),old.login_date_last) login_date_last,
	IF (new.user_id IS NOT NULL,new.active_count,0) login_day_count,
	nvl (old.login_count, 0) +nvl (new.active_count, 0) login_count,
	nvl (old.log_count, 0) +IF (new.active_count > 0, 1, 0) log_count,
	nvl (new.is_visitor, old.is_visitor) is_visitor
FROM
	(SELECT * FROM dwt_user_active_topic) old
	FULL OUTER JOIN 
	(SELECT u1.*,u2.parent_id parent_app_id FROM dws_user_active_daily u1
	LEFT JOIN ods_app_config u2 on u1.app_id = u2.app_id 
    WHERE dt = '$first') new ON old.user_id = new.user_id and new.parent_app_id = old.parent_app_id;"
echo $sql_topic

first=`date -d "-1 days ago ${first}" +%Y-%m-%d`

$hive -e "$sql_topic"
done

执行补充中。。。。。

### Hive SQL 中特殊字符的使用方法与处理技巧 在 Hive SQL日常开发过程中,经常会遇到需要处理字符串中的特殊字符的情况。这些特殊字符可能会影响查询逻辑或者数据解析的结果。因此,掌握如何正确识别、匹配以及转义这些特殊字符至关重要。 #### 1. 常见特殊字符及其含义 Hive SQL 支持多种特殊字符用于正则表达式或其他字符串操作场景。以下是部分常用特殊字符及其功能说明: | 特殊字符 | 描述 | |----------|--------------------------| | `\f` | 匹配一个换页符 | | `\n` | 匹配一个换行符 | | `\r` | 匹配一个回车符 | | `\t` | 匹配一个水平制表符 | | `\v` | 匹配一个垂直制表符 | 上述特殊字符通常被用来定义分隔符或过滤条件,在涉及复杂文本文件的数据加载和清洗阶段尤为重要[^3]。 --- #### 2. 字符串中查找特定字符的位置 为了定位字符串内的某一部分内容,可以利用 `INSTR()` 函数来实现这一目标。该函数返回子字符串首次出现的位置索引(从 1 开始计数),如果未找到,则返回 0。例如: ```sql SELECT INSTR('hello world', 'o') AS position; -- 输出结果:position=5 ``` 此函数适用于简单模式下的单个字符检索任务;对于更复杂的多字符组合搜索需求,则需借助其他工具完成进一步扩展[^1]。 --- #### 3. 正则表达式的应用 当面对更加灵活的需求时——比如提取包含某些指定格式字段的信息片段或是验证输入是否符合预期标准等情况之下—我们还可以考虑采用支持Perl兼容语法风格的强大武器REGEXP/RLIKE语句来进行精确控制: - **REGEXP**: 判断列值是否满足给定模式的要求. ```sql SELECT * FROM table_name WHERE column REGEXP '^\\d+$'; -- 只保留全数字类型的记录 ``` - **CONCAT_WS & SPLIT**: 结合这两个命令能够轻松拆解并重新组装由固定标志位分割开来的各项单元格成员. ```sql WITH sample_data AS ( SELECT CONCAT_WS(',', 'a', 'b', 'c') as str_val ) SELECT split(str_val, ',')[0], split(str_val, ',')[1] FROM sample_data; -- 返回 a 和 b 分别位于不同列之中 ``` 以上实例展示了通过运用高级特性达成精细化管理目的可能性[^2]. --- #### 4. 转义机制详解 由于许多情况下原始资料里本身就存在干扰正常运算流程执行路径上的障碍物(即所谓的"元字符"),所以适时采取必要的防护措施就显得尤为必要了.一般而言我们会选用反斜杠(\)作为前缀附加到待保护的目标对象之前形成新的序列从而达到规避风险的效果: ```sql SELECT regexp_replace('abc*def$', '\\*', '_STAR_'); -- 将星号(*)替换成_STAR_ ``` 值得注意的是并非所有的数据库引擎都遵循完全一致的行为准则所以在跨平台迁移项目期间务必仔细核对文档确认细节差异之处以免造成不必要的麻烦. --- ### 总结 综上所述,Hive提供了丰富的手段帮助开发者高效解决围绕着各类奇特符号所带来的挑战问题不仅限于基础层面还包括深层次的应用范畴等待大家去探索发现更多有趣的功能点吧!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值