HiveSQL编程模板及注意事项

目录

0 引言

1 模板代码

2 代码分析及注意事项


0 引言

hive是数据仓库、数据分析人员必用的工具之一。实际工作中,使用hive很多时候都是在将SQL代码封装在shell脚本之下运行,这是一种常见的方式,方便调度工具调度shell脚本。

1 模板代码

#!/bin/bash
lastday=`date --date '-1days' +%Y-%m-%d` #获得昨天的日期
if [ "$2" != "" ];then
   lastday=$2
fi;
input_para="hive" #默认启动方式
if [ "$1" != "" ];then
   input_para=$1
fi;
#UDF函数使用形式
sqlFun1="CREATE TEMPORARY FUNCTION avgCalShock AS 'jttl.jxresearch.com.hive.udf.avgCalShock' using jar 'hdfs:///phm/JTTL_ETL_COMMON/jx-yjy-udfs-1.0-SNAPSHOT.jar'";
sqlFun2="CREATE TEMPORARY FUNCTION maxCalShock AS 'jttl.jxresearch.com.hive.udf.maxCalShock' using jar 'hdfs:///phm/JTTL_ETL_COMMON/jx-yjy-udfs-1.0-SNAPSHOT.jar'";
sqlFun3="CREATE TEMPORARY FUNCTION minCalShock AS 'jttl.jxresearch.com.hive.udf.minCalShock' using jar 'hdfs:///phm/JTTL_ETL_COMMON/jx-yjy-udfs-1.0-SNAPSHOT.jar'";

input_table="phmdwdb.dwd_iot_phm_switch_shock"; #输入表名
output_table="phmdwdb.dwd_phm_switch_shock_event"; #输出表名
log_dir=${output_table:8};

#Hive的连接方式参数获取(本方案采用oozie传参,也可以将参数放到hdfs上然后获取)
option=`echo ${input_para} | awk -F '_' '{print $1}' | sed s/[[:space:]]//g`
#SQL需要的参数获取
guoche_top_num=`echo ${input_para} | awk -F '_' '{print $3}' | sed s/[[:space:]]//g`


hive_home='/usr/idp/current/hive-client/bin';


sql="
 insert overwrite TABLE $output_table
 PARTITION (compute_day='$lastday') --注意sql中需要引用shell变量且为字符串时候,此处必须为单引号,使用双引号结果会显示不正确
 select
       XXX
      ,XXX
      ,XXX
 from ${input_table}
 where from_unixtime(cast(substr(msg_time,1,10) as bigint),'yyyy-MM-dd')='$lastday'
 
 ;
";

if [ "$option" = "beeline" ];then
   # hive2地址获取
   hive_addr=`hadoop fs -cat /phm/JTTL_ETL_COMMON/jdbc.properties | grep hive_addr | awk -F '=' '{print $2}' | sed s/[[:space:]]//g`
   hive_url="${hive_addr}/phmdwdb"
   cd $hive_home
   beeline -u $hive_url -e "$sqlFun1;$sqlFun2;$sqlFun3;$sql"  >>/tmp/$log_dir.log  2>&1 ;
fi

if [ "$option" = "hive" ];then

   hive -e "$sqlFun1;$sqlFun2;$sqlFun3;$sql"  >>/tmp/$log_dir.log  2>&1 ;
fi
#注意使用hive -e "$sql" 而不是hive -e $sql,$sql前必须有双引号。另外日志文件名必须和>>及$sql在同一行。

2 代码分析及注意事项

(1)hive -e方式

hive -e "待执行sql"。这种方式允许我们在引号中写入需要执行的SQL语句。通常适合于语句较长的情况。这种方式也是在需要进行任务调度时采用的最直接方式,此时可以结合shell定义可变参数(如日期),再结合调度系统就可以实现脚本自动化。

hive -e遇到竖线分割时(特殊符号),要加多个转义符

先来看交互式命令行的方式。

假设我们要取出每个用户的城市和性别,使用split函数,可能会采用以下写法:

select split(location_city, '|')[0] as city,split(location_city, '|')[1] as genderfrom test_0102;

结果如下图所示。

显然结果不是我们想要的,这是因为竖线比较特殊。我们加上转义符再来看下。

select 
split(location_city, '\|')[0] as city,
split(location_city, '\|')[1] as gender
from test_0102;

结果如下:

 结果并未发生变化,不符合预期。如果再加一个转义符。

select 
split(location_city, '\\|')[0] as city,
split(location_city, '\\|')[1] as gender
from test_0102;

结果如下:

综上实验可以看到我们最终的结果通过加两个//后 得到我们想要的结果。这是由于第一个转义符是从 hive -> MapReduce 过程的转义第二个转义符是 MapReduce 编译时的转义。

再来看使用hive -e的方式执行。如果直接用两个转义符,输出的结果仍然是把单字分隔开。

 这是因为从shell到hive多了一步转义。因此需多加一个转义符。实际上,如果使用四个转义符,结果依然正确。具体规律直接给出:

令需要转义符的个数为 y
如何目标字符串包含'\',则  y = 2^n 
如何目标字符串不包含'\',则 y = n 
n:跨框架调用的次数,最终算到 java编译为止,一般最常见的就是上面两种情况。

参考链接:https://blog.csdn.net/lt793843439/article/details/91492088

相应的,如果遇到双竖线的情况,对每一个竖线则需要分别转义。例如我们要将上面数据中skills一列分割出来。相应写法如下

  • hive命令行:每一个竖线两个转义符

图片

  • hive -e:每一个竖线三个转义符(四个也行)

图片

(2)hive -e 生成结果文件时,文件名要和重定向符放在一行

         hive -e执行hiveSQL时,可以采用重定向符(>)把查询结果写入文件。

hive -e"use dac_twelve_dev;select split(location_city, '\\\|')[0] as city,split(location_city, '\\\|')[1] as genderfrom test_0102;" > test_0102.txt
cat test_0102.txt北京  男上海  女北京  男广州  女西安  男

需要注意的是,结尾的双引号,重定向符号,结果文件文件名和要放在同一行。否则则可能不能如期生成结果文件。如下面几种方式所示。

#第一种hive -e"your SQL" > test_0102.txt
#第二种hive -e"your SQL" > test_0102.txt
#第三种hive -e"your SQL" > test_0102.txt

上面的三种方式,第一种会报错:-bash: syntax error near unexpected token `newline。第二种会在屏幕上打印结果后报相同的错,第三种会在屏幕上打印结果不报错,但最终结果文件没有数据。

(3)shell中执行hiveSQL打印SQL时注意星号

在调度中运行hiveSQL时,一般会使用shell脚本文件。脚本中先定义好时间变量,再定义SQL语句,最后使用hive -e方式执行SQL。类似于下面这样:

yesterday=`date -d "now -1 day" +%Y-%m-%d`hql="select * from xxt_able where ds='${yesterday}'"echo $hql#错误的写法,正确的是echo "$hql"hive -e $hql > result.txt

这里需要注意的是如果定义的hql语句中有*号(等特殊符号),为了在echo打印时能够正常输出,以便于我们核查时间变量是否被正确替换。需要用"$hql" 而不要使用$hql否则在打印的时候,*号会被当做shell的通配符,把当前路径下所有的文件名称都打印出来。同样也会hive在运行时报错。如下面代码和结果所示。*在打印时被替换为了当前路径下所有的文件。

图片

图片

(4)关于hive执行时的其他选项

  • -S选项屏蔽mapreduce日志

执行hiveSQL时,如果需要执行MapReduce过程,屏幕上会出现类似于map=100%,reduce=33%这样的提示,如果任务比较复杂,日志长度也会相应增加。虽然能便于我们了解任务进度,但有时我们也会想把它屏蔽掉。使用hive -S -e "sql语句"的方式,以Silent mode运行hive,就可以实现这样的目,此时屏幕上只会有hive启动的日志,而不会有mapreduce过程的日志。

图片

  • -v选项打印出实际执行的SQL(调试SQL使用,一般会在shell脚本层使用sh -v +脚本名来调试)

图片

这个选项可以用于前面提到的任务调度时,验证实际执行的详细SQL。假设我们提前定义好yesterday变量,-v选项会将变量值打印出来,也就替代了echo "$hql"的方式。(这里SQL报错了,我们为了演示变量,引用了表中不存在的ds字段)

图片

 (5)SQL脚本中引用shell中的变量且为字符串时需要使用单引号

   1)Shell中单引号和双引号区别

  •    编辑脚本
#!/bin/bash
do_date=$1

echo '$do_date'
echo "$do_date"
echo "'$do_date'"
echo '"$do_date"'
echo ""$do_date""
echo ''$do_date''
echo `date`
  • 测试脚本,结果如下
[root@bigdata-1 dan_test]# ./test3.sh '2021-01-04'
$do_date
2021-01-04
'2021-01-04'
"$do_date"
2021-01-04
2021-01-04
2021年 01月 04日 星期一 20:39:41 CST
  • 总结:
  • 双引号:取$变量值。
  • 单引号:原样输出,里面是什么输出什么,不取变量值

(1)单引号不取变量值,原样输出

(2)双引号取变量值。

(3)双引号内部嵌套单引号,取出变量值,变量值整体被取出后显示单引号会被作为字符串。

(4)单引号内部嵌套双引号,不取出变量值,将双引号内内容整体当作字符串输出

(5)双引号内嵌套双引号,取出变量值,但不显示双引号,整体输出不会作为字符串,双引号被抵消掉,相当于${变量}。

(6)单引号内嵌套单引号,取出变量值,但不显示单引号,整体输出不会作为字符串,单引号被抵消掉,相当于${变量}。

(7)反引号`,执行引号中命令

整体总结:双引号与单引号交替出现,看外层,如果外层是双引号则具备双引号取变量值的功能,且显示单引号。如果外层是单引号则原样输出。

        双引号或单引号成对出现:此时无论单引号还是双引号将会被抵消掉,相当于${变量值}

        双引号单引号交替出现,但双引号或单引号成偶数出现时,此时主要看外层,外层是双引号则抵消双引号,$里面的值会被解析,此时显示抵消掉双引号后的内容(不常用)

        如果外层是单引号,则抵消的是单引号,$里面的值会被解析,此时显示抵消掉单引号后的内容(不常用)
#!/bin/bash

a=110

sql11=" " " '$a' " " "

echo $sql11

~

#!/bin/bash

a=110

sql11=' " " " '$a' " " " '

echo $sql11

#!/bin/bash

a=110

sql11=' " " "$a" " " '

echo $sql11

#!/bin/bash

a=110

sql11=" ' " " "$a" " " ' "

echo $sql11

对于非交替而是外层连续出现的则和成对出现情况一样
 

#!/bin/bash

a=110

sql11=' ' """"$a"""" ' '

echo $sql11

#!/bin/bash

a=110

sql11=' " '$a' " '

echo $sql11

#!/bin/bash

a=110

sql11=" ' "$a" ' "(会被用到)

echo $sql11

如下脚本:

2)SQL脚本中往往需要将带“-”的时间进行字符串形式输出,此时需要加单引号而不是双引号。

where中需要按天过滤必须要加引号否则会不识别,时间输出时候必须要加引号否则会输出乱码

 

 

参考链接:https://mp.weixin.qq.com/s/_18inMSkJKCBCCYWbDLJPw

猜你喜欢

转载自blog.csdn.net/godlovedaniel/article/details/112196874