作者介绍

莲石东路@乌森

心之所向,***成长。从底层架构到应用实战,聊聊炼数成金背后的故事。

持续更新数据治理、数据科学、数据可视化、空间计算系列文章。

01 前言

公司新入职了的产品经理小美因为业务需要,想搭一个数据大屏方便自己查看数据。她找开发小王申请了数仓权限,然后从技术中台里找到了数据大屏的工具,把自己平时查数据用的sql搬上去跑,结果总是报错。

从0开始搭建数据仓库(2):产品经理如何“玩转”Hive SQL
小美找到了做数据产品经理的师兄小帅看了看。
小帅:你这个查询有问题,业务系统的sql不能直接搬来用。
小美:我看长得差不多啊,除了多了个分区外,不都是sql吗?
小帅:你现在建的是Hive查询,Hive SQL虽说和SQL非常相似,但是一些细节上还是有区别的。

02 Hive SQL是什么?

Hive是大数据领域常用的数据仓库组件,可以借助查询语言SQl将HDFS上存储的结构化文件映射成一张数据库表,并提供类SQL查询功能。Hive-SQL就是这个”类SQL查询功能”。Hive-SQL与SQL基本上一样,因为当初的设计目的,就是让会SQL不会编程MapReduce的也能完成处理数据工作。
【拓展】Hive-SQL是如何转化为MapReduce任务的呢?整个编译过程分为六个阶段:

1) Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree
2) 遍历AST Tree,抽象出查询的基本组成单元QueryBlock
3) 遍历QueryBlock,翻译为执行操作树OperatorTree
4) 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量
5) 遍历OperatorTree,翻译为MapReduce任务
6)物理层优化器进行MapReduce任务的变换,生成最终的执行计划

这里简单介绍一下其中的几个关键部分:
Antlr:Antlr是一种语言识别的工具,用来实现SQL的词法和语法解析,完成包括词法分析、语法分析、语义分析、中间代码生成等过程。使用时只需要编写对应的语法文件,定义词法和语法替换规则即可。
抽象语法树AST Tree:经过词法和语法解析后,使用 Antlr 的抽象语法树语法Abstract Syntax Tree,将输入语句转换成抽象语法树,方便后续进一步的处理。
QueryBlock:AST Tree仍然非常复杂,不够结构化,不方便直接翻译为MapReduce程序,AST Tree转化为QueryBlock就是将SQL进一步抽象和结构化。QueryBlock是一条SQL最基本的组成单元,包括三个部分:输入源,计算过程,输出。简单来讲一个QueryBlock就是一个子查询。我们在查看HiveSQL查询日志时会看到一个个流程块,这就是分拆出来的QueryBlock。

从0开始搭建数据仓库(2):产品经理如何“玩转”Hive SQL

03 Hive SQL基本语法

小美的查询语句中用了HAVING子句,这个是Hive不支持的,可以用子查询来代替。然后小帅为小美讲了讲HiveSQL的基本语法。

常用的显示命令

show databases; -- 查看有哪些库
show tables; -- 查看当前库下有哪些表
show partitions; -- 查看分区
show functions; -- 罗列所有的函数
describe extended table_name; -- 查看表的结构,字段,分区等情况
常用库、表操作

create database name; -- 创建数据库
create [external]table [if not exists] table_name --创建表,指定表名。external 表示创建的表是否为外部表,不加此项则为内部表。if not exists 表示该表不存在时创建该表,否则忽略异常。
​[(col_name data_type [comment col_comment], ...)] -- 创建字段,指定字段类型、注释
​[comment table_comment] -- 表的注释
​[partitioned by(col_name data_type [comment col_comment], col_name_2 data_type_2, ...)] -- 指定分区,要注意分区字段不能出现的建表的字段中
​[clustered by(col_name, col_name_2, ...)] [sorted by (col_name [ASC|DESC], ...)] into num_buckets buckets] -- 分桶
​[row format row_format]
​[stored as file_format] -- 指定存储文件类型。textfile纯文本数据,sequencefil压缩数据(可节省存储空间)。
​[location hdfs_path] -- 存储路径
​create table table_name like old_table_name; -- 使用like关键字复制表结构
​alter table table_name rename to new_table_name; -- 更改表名
​alter table table_name add columns (col_name data_type comment 'col_comment'); -- 增加一个字段并添加注释
​alter table table_name replace columns (col_name data_type, col_name_2 data_type_2); -- 删除列
​alter table table_name add [if not exists] partition_name; -- 增加分区
​alter table table_name drop partition_name, partition_name_2; -- 删除分区
常用数据操作

insert into table_1 select from table_2; -- 在table_1后追加数据
insert overwrite table_1 select
from table_2; -- 先将table_1中数据清空,然后添加数据
常用查询操作

HiveSQL的查询语句结构和SQL一致,除了前面提到的HAVING子句问题外,还需要注意的是HiveSQL中没有not null,当字段为null时,使用\n代替。

04 Hive SQL常用函数

小美的查询中有两处函数调用错误:
1) 用了GROUP_CONCAT()函数,这个在HiveSQL中没有,但是可以用CONCAT_WS()函数代替;
2) 是substring_index()函数,这个应该替换成split()函数。
然后小帅为小美讲了讲Hive中的常用函数。
数学函数

bin(int d) -- 计算二进制值d的string值
rand(int seed) -- 返回随机数,seed是随机因子
round(double d,int n) -- 返回保留n位小数的近似d值
floor(double d) -- 返回小于d的最大整值
ceil(double d) -- 返回大于d的最小整值
日期函数

current_date() -- 返回当前日期
unix_timestamp() -- 返回当前时间的unix时间戳,也可指定某一特定日期。如unix_timestamp('2021-01-13','yyyy-mm-dd')=1610513364
from_unixtime() -- 返回unix时间戳的日期。如selectfrom_unixtime(unix_timestamp('2021-01-13','yyyy-mm-dd'),'yyyymmdd')='20210113'
to_date(string timestamp) -- 返回时间字符串中的日期部分,如to_date('2021-01-0100:00:00')='2021-01-01'
year(date) -- 返回日期date的年,如year('2021-01-01')=2021
month(date) -- 返回日期date的月,如month('2021-01-01')=1
day(date) -- 返回日期date的天,如day('2021-01-01')=1
weekofyear(date) -- 返回日期date位于该年第几周,如weekofyear('2021-01-01')=1
datediff(date1, date2) -- 返回日期date1与date2相差的天数,如datediff('2021-01-01','2021-01-02')=1
date_add(date,int1) -- 返回日期date加上int1的日期,如date_add('2021-01-01',2)='2021-01-03'
date_sub(date,int1) -- 返回日期date减去int1的日期,如date_sub('2021-01-03',2)='2021-01-01'
months_between(date1,date2) -- 返回date1与date2相差月份,如months_between('2021-03-01','2021-01-01')=2
add_months(date,int1) -- 返回date加上int1个月的日期,int1可为负数。如add_months('2021-02-01',-1)='2021-01-01'
last_day(date) -- 返回date所在月份最后一天。如last_day('2021-01-01')='2021-01-31'
next_day(date,day1) -- 返回日期date后下个星期day1的日期。day1为星期X的英文前两字母如next_day('2021-01-013','MO') 返回'2021-01-18'
trunc(date,string1) -- 返回日期所在月的第一天或所在年的第一天。String1可为年(YYYY/YY/YEAR)或月(MONTH/MON/MM)。如trunc('2021-01-13','MM')='2021-01-01',trunc('2021-02-01','YYYY')='2021-01-01'
字符串函数

length(string) -- 返回字符串长度
concat(string1,string2) -- 返回拼接string1及string2后的字符串
concat_ws(sep, string1,string2) -- 返回按指定分隔符sep拼接后的字符串
lower(string) -- 返回小写字符串,同lcase(string)。
upper(string) -- 返回大写字符串,同ucase(string)。
ascii(string) -- 返回字符串第一个字符的ascii值。
space(int1) -- 返回int1长度的空格字符串。
trim(string) -- 去掉字符串左右空格。
ltrim(string) -- 去掉字符串左空格。
rtrim(string) -- 去掉字符串右空格。
repeat(string,int1) -- 返回重复string字符串int1次后的字符串。
reverse(string) -- 返回string反转后的字符串。如reverse('abc')='cba'
lpad(string,len1,pad1) -- 以pad1字符左填充string字符串,至len1长度。如rpad('abc',5,'1')='11abc'。
rpad(string,len1,pad1) -- 以pad1字符右填充string字符串,至len1长度。如rpad('abc',5,'1')='abc11'。
split(string,pat1) -- 以pat1正则分隔字符串string,返回数组。如split('a,b,c',',') = ["a","b","c"]
substr(string,index1,int1) -- 从index位置起截取int1个字符。如substr('abcde',1,2)='ab'
regexp_replace(string1,string2, string4) --正则表达式替换函数。将字符串1中的符合正则表达式string2的部分替换为string3。如regexp_replace(‘abcde, ‘b|c|d’, ”)=’ae’
聚合函数

count(col) -- 统计行数
sum(col) -- 统计指定列和
avg(col) -- 统计指定列平均值
min(col) -- 返回指定列最小值
max(col) -- 返回指定列最大值
窗口函数

row_number() over(partitiion by .. order by .. ) -- 根据partition排序,相同值取不同序号,不存在序号跳跃
rank() over(partition by .. order by ..) -- 根据partition排序,相同值取相同序号,存在序号跳跃
dense_rank() over(partition by .. order by ..) -- 根据partition排序,相同值取相同序号,不存在序号跳跃
lag(col,n) over(partition by .. order by ..) --查看当前行的上第n行
lead(col,n) over(partition by .. order by ..) -- 查看当前行的下第n行
转换函数

cast(col as dtype) --将指定值转换为指定数据类型dtype,如字符串到整型的转换
判断函数

NVL(expr1, expr2) -- 如果第一个参数为空则显示第二个参数,反之则显示第一个参数。常用于非空判断,如nvl(table1.name, '') <> ''
NVL2(expr1, expr2,expr3) -- 如果第一个参数为空则显示第二个参数,反之则显示第三个参数
NULLIF(expr1, expr2) -- 如果第一个参数和第二个参数相等则返回空(NULL),否则返回第一个参数
Coalesce(expr1,expr2, expr3….exprn) -- 返回参数序列中第一个非空参数

解析函数

regexp_extract(string1,string pattern, int1) -- 正则表达式解析函数。将字符串string1按照正则表达式pattern的规则拆分,返回int1指定的字符。如regexp_extract(‘foothebar’, ‘foo(.?)(bar)’, 1)=’the’,regexp_extract(‘foothebar’, ‘foo(.?)(bar)’, 2)=’bar’
Size(map(<key,value>,<key,value>)) -- 返回map集合的个数。如size(map(1,’a’,2,’b’))=2。
find_in_set(string1, string strList) -- 返回string1在strlist中第一次出现的位置,strlist是用逗号分割的字符串(集合)。如果没有找string1,则返回0.
parse_url(string url_string, stringpartToExtract [, string keyToExtract]) --url解析函数,partToExtract的有效值为:HOST,PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO。如parse_url(‘http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1′,‘HOST’)=‘facebook.com’,parse_url(‘http://facebook.com/path1/p.php?k1=v1
&k2=v2#Ref1′,‘QUERY’, ‘k1′)=’v1’
get_json_object(string json_string,string path) -- json解析函数。解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。

行列转换

concat_ws(sep, collect_set(col1)) -- 多行转一列,以sep分隔符分隔。collect_set在无重复的情况下也可以collect_list()代替。collect_set()去重,collect_list()不去重
lateral view explode(split(col1, sep)) -- 一列转多行。

05 后记

小美根据记下的笔记自己尝试,终于完成的数据大屏的搭建。

一个数据人的自留地是一个助力数据人成长的大家庭,帮助对数据感兴趣的伙伴们明确学习方向、精准提升技能。关注我,带你探索数据的神奇奥秘

1、回“数据产品”,获取<大厂数据产品面试题>

2、回“数据中台”,获取<大厂数据中台资料>

3、回“商业分析”,获取<大厂商业分析面试题>;

4、回“交个朋友”,进交流群,认识更多的数据小伙伴。

更多相关文章

  1. navicate premium 如何导入excel表数据
  2. 初始化 Java 数据字段(学习 Java 编程语言 033)
  3. 六一儿童节,送你一个F字符串
  4. 数据库两大神器【索引和锁】
  5. Navicat实用功能:数据备份与结构同步
  6. 我们到底该如何学习数据结构与算法
  7. 干货丨时序数据库DolphinDB异常检测引擎教程

随机推荐

  1. android 建数据库 SQLite 存储sd 卡或者
  2. Android应用程序进程启动过程的源代码分
  3. Android网络连接判断与处理
  4. 安卓布局之线性布局(Linearlayout)
  5. Android EditText取消自动焦点获取
  6. 【Android】Android Layout Binder——根
  7. android 绘图
  8. PreferenceActivity、PreferenceFragment
  9. Python on Android
  10. Android关闭多个activity