0


hive sql -- 看完就会了!

前言

** 想与你们共同学习,想与你们一起努力,想得到你们的支持与喜欢~**

hivesql与sql区别:

1、mysql采用了sql语言,hive采用了类sql的查询语言hql。

2、hive不支持数据的改写和添加,mysql支持。

3、hive无索引,mysql有索引。

4、hive底层是marreduce,mysql底层是执行引擎。

5、hive存储的数据量超级大,而mysql只是存储一些少量的业务数据。

6、hive是把数据存储到hdfs,而mysql数据存储在自己的系统中。

7、hive数据格式可以用户自定义,mysql有自己的系统定义格式。

8、hive支持按行分割,按字段分割,如按‘,’分割:lateral view explode(split( , ','))

9、Hive适用于大数据批处理,通常需要一些时间来处理和分析大量数据。MySQL通常适用于在线事务处理(OLTP),需要快速处理和检索少量数据。

** SQL的书写顺序:**

select ... from ... where ... group by ... having ... order by ... limit

SQL关键词执行顺序:

from > where条件 > group by > having条件 > select >order by>limit

【注意】sql一旦出现group by,后续的关键词能够操作字段只有(分组依据字段,组函数处理结果)

1.基本查询

# 1. 各个数据类型的字段访问(array、map、struct)
select name,salary,hobbies[1],cards['中国银行'],addr.city from t_person;
# 2. 条件查询:= != >= <=
select * from t_person where addr.city='郑州';
# 3. and 、 or 、between and
select * from t_person where salary>5000 and array_contains(hobbies,'抽烟');
# 4. order by[底层会启动mapreduce进行排序]
select * from t_person order by salary desc;
# 5. limit(hive没有起始下标)
select * from t_person sort by salary desc limit 5; 
# 6. 去重
select distinct addr.city  from t_person;
select distinct(addr.city) from t_person;

2.表连接

-- 创建部门表
create table dept(
deptno int,
dname string,
loc string
)
row format delimited fields terminated by '\t';
-- 创建员工表
create table  emp(
empno int,
ename string,
job string,
mgr int,
hiredate string, 
sal double, 
comm double,
deptno int)
row format delimited fields terminated by '\t';
-- 导入数据
load data local inpath '/opt/data/dept.txt' into table dept;
load data local inpath '/opt/data/emp.txt' into table emp;

dept.txt包含数据
10      ACCOUNTING      NEW YORK
20      RESEARCH        DALLAS
30      SALES   CHICAGO
40      OPERATIONS      BOSTON

emp.txt包含数据
7369    SMITH    CLERK    7902    1980-12-17    800.00        20
7499    ALLEN    SALESMAN    7698    1981-02-20    1600.00    300.00    30
7521    WARD    SALESMAN    7698    1981-02-22    1250.00    500.00    30
7566    JONES    MANAGER    7839    1981-04-02    2975.00        20
7654    MARTIN    SALESMAN    7698    1981-09-28    1250.00    1400.00    30
7698    BLAKE    MANAGER    7839    1981-05-01    2850.00        30
7782    CLARK    MANAGER    7839    1981-06-09    2450.00        10
7788    SCOTT    ANALYST    7566    1987-04-19    3000.00        20
7839    KING    PRESIDENT        1981-11-17    5000.00        10
7844    TURNER    SALESMAN    7698    1981-09-08    1500.00    0.00    30
7876    ADAMS    CLERK    7788    1987-05-23    1100.00        20
7900    JAMES    CLERK    7698    1981-12-03    950.00        30
7902    FORD    ANALYST    7566    1981-12-03    3000.00        20
7934    MILLER    CLERK    7782    1982-01-23    1300.00        10
7935    张三    CLERK    7782    1986-01-23    1300.00        
  • 左连接
select e.empno, e.ename, d.deptno from emp e left join dept d on e.deptno = d.deptno;
  • 内连接
select e.empno, e.ename, d.deptno from emp e inner join dept d on e.deptno = d.deptno;
  • 右连接
select e.empno, e.ename, d.deptno from emp e right join dept d on e.deptno = d.deptno;
  • 全连接
select e.empno, e.ename, d.deptno from emp e full join dept d on e.deptno = d.deptno;

3.分组

强调:一旦使用group by之后,则select后边可以写: 1.分组的字段 2.聚合函数 3.常量值

1. group by(查看各个城市的均薪)
select addr.city,avg(salary) from t_person group by addr.city;
2. having(查看平均工资超过5000的城市和均薪)
select addr.city,avg(salary) from t_person group by addr.city having avg(salary)>5000;

4.单行函数

-- 查看系统自带的函数
show functions;
-- 显示函数的用法
desc function upper;
-- 详细显示自带的函数的用法
desc function extended upper;

函数:单行函数(UDF)、聚合函数(UDAF)、炸裂函数(UDTF)

数值函数

1. round: 四舍五入
select round(3.1414,2)  -- 输出3.14

2. ceil : 向上取整
select ceil(3.1415)     -- 输出4

3. floor: 向下取整
select floor(3.1415)    -- 输出3

4. cast(expr as <type>) : 类型转换  [重点]
select cast('1' as bigint)   -- Integer.parseInt('1')

字符串函数

1. length:字符串长度
select length('abcde')   -- 输出5

2. concat:字符串连接
select concat('张三','李四','王五')   -- 输出张三李四王五

3. concat_ws:带分隔符的字符串连接
select concat_ws('-','李四','王五','赵六')   -- 输出李四-王五-赵六
select name,hobbies,concat_ws('-',hobbies) from t_person  -- 将数组拼接成一个字符串

concat和concat_ws有什么区别?
1. 功能描述他们的区别
2. concat拼接的字符串中有null,在最终拼接结果是空,concat_ws拼接字符串有空,不影响拼接结果,去除空

4. substr / substring:字符串截取
select substring('张无忌',1,1)  -- 输出张,参数是下标,从1开始,参数2代表截取长度

5. upper:字符串转大写
select UPPER('abc')   -- 输出ABC

6. lower:字符串转小写
select lower('AbC')    --输出abc

7. trim / ltrim / rtrim:取出空格/左空格/右空格
select length(trim(' abc '))    -- 输出: 3

8. split:分割字符串
select split('中国-美国-日本','-')   -- split函数的返回值是一个数组

9. replace:替换字符串
select replace('蔡徐坤喜欢打篮球','篮球','足球')  -- 替换指定字符串
select replace('蔡徐坤 喜欢 打篮球',' ','')      -- 去除空格

10. regexp_replace:正则替换
select regexp_replace('abc-123-ab-456-cd', '[0-9]+', '*');

11. get_json_object:从路径中提取json对象
select get_json_object('{"name":"张三","age":20}','$.name')
select get_json_object('{"name":"张三","age":20,"hobbies":["唱","跳"]}','$.hobbies[0]')

json是一种存储(传输)数据的格式,存储方式比较简单,所以受到it行业的广泛推广
1. xml和json对比
xml存储  <student>
                 <name>zs</name>
                 <age>20</age>
         </student>
json存储 {"name":"zs","age":20}

2. json的语法格式就两种
1. json对象(大括号) {"属性名":属性值,"属性名2":属性值}
   例如:{"name":"zs","age":20}
2. json数组 (中括号)  [值1,值2,值3]
   例如:["张三","李四","王五"]

存储3个人的信息(姓名+年龄+爱好)
[{"name":"zs","age":20,"hobbies":["唱","跳","Rap"]},
 {"name":"李四","age":22,"hobbies":["唱","跳","Rap"]},
 {"name":"王五","age":23,"hobbies":["抽烟","喝酒","烫头"]}]
 

流程控制函数

1. case when:条件判断  【重要】
-- 大于8000,输出缴税交20%
-- 大于5000,输出缴税交10%
-- 否则不用缴税
select  name,salary,
        case when salary >= 8000 then  salary*0.2
             when salary >= 5000 then  salary*0.1
             else 0 end  x1
from t_person 

2. if:条件判断,类似Java中的三目运算符 条件 ? 值1:值2
语法:if(条件,值1,值2)
select name,sex,if(sex=0,'女',if(sex = 1, '男','人妖')) from t_person

3. nvl(值1,值2): 如果值1不是空输出值1,否则输出值2
select nvl('a','b')   -- a
select nvl(null,'b')  -- b

select ename,sal+nvl(comm,0) from emp

日期时间函数

1.datediff:日期比较  【重要】
select datediff('2023-10-03','2023-10-01') -- 输出2

2.date_add / date_sub:日期增加/日期减少 【重要】
select date_add('2023-10-03',1)   -- 输出2023-10-04
select date_sub('2023-10-03',1)   -- 输出2023-10-02

select add_months('2023-12-03',1)  -- 2024-01-03
select cast('2023-10-03' as date) + interval 1 year  -- 2024-10-03

3.unix_timestamp:获取当前 UNIX 时间戳函数
select unix_timestamp() -- 获取当前系统时间的时间戳,单位是秒
-- 指定时间转换的时间戳差8个时区,可以通过下面函数处理
SELECT unix_timestamp(to_utc_timestamp ('2022-07-26 09:22:39','GMT+8'),'yyyy-MM-dd HH:mm:ss');

4.from_unixtime:转化unix时间戳到当前市区的时间
select from_unixtime(1700015310)         -- 返回的是UTC(国际协调时间)时间,和中国相差了8个小时
select from_unixtime(cast(1700015310 as bigint) + 28800)

5.current_date:当前日期
select current_date();  -- 例如输出 2023-11-15

6.current_timestamp:当前日期加时间,精确到毫秒
select current_timestamp();  -- 例如输出 2024-05-17 16:25:07.544000000

集合函数

1. size:集合中元素的个数
select name,hobbies,size(hobbies) from t_person 

2. map:创建map集合
select map('name','zs','age',20)

3. map_keys:返回map中的key
select map_keys(cards) from t_person 

4. array_contains:判断array中是否包含某个元素
select name,hobbies,array_contains(hobbies,'抽烟') from t_person 

5.聚合函数

# 聚合函数
概念:
max、min、sum、avg、count、collect_list、collect_set等。

select max(salary) from t_person where addr.city='北京';
select count(id) from t_person;

**

collect_list、collect_set:

**

--## 表(电影观看日志)
create table t_visit_video (
    username string,
    video_name string,
    video_date date
)row format delimited fields terminated by ',';
--## 数据:豆瓣观影日志数据。(用户观影日志数据  按照天存放 1天一个日志文件)
张三,大唐双龙传,2020-03-21
李四,天下无贼,2020-03-21
张三,神探狄仁杰,2020-03-21
李四,霸王别姬,2020-03-21
李四,霸王别姬,2020-03-21
王五,机器人总动员,2020-03-21
王五,放牛班的春天,2020-03-21
王五,盗梦空间,2020-03-21
# collect_list
作用:对分组后的,每个组的某个列的值进行收集汇总。
语法:select collect_list(列) from 表 group by 分组列;

select username,collect_list(video_name) from t_visit_video group by username;
# collect_set
作用:对分组后的,每个组的某个列的值进行收集汇总,并去掉重复值。
语法:select collect_set(列) from 表 group by 分组列;

select username,collect_set(video_name) from t_visit_video group by username;

6.炸裂函数

-- 查询所有的爱好,
select explode(hobbies) as hobby from t_person
# lateral view 
定义:lateral view通常与UDTF配合使用。lateral view可以将UDTF应用到源表的每行数据,将每行数据转换为一行或多行,
      并将源表中每行的输出结果与该行连接起来,形成一个虚拟表。

-- 为指定表,的边缘拼接一个列。(类似表连接)
-- lateral view:为表的拼接一个列(炸裂结果)
-- 语法:from 表 lateral view explode(数组字段) 别名 as 字段名;
-- 查看id,name,爱好。一个爱好一条信息。
select id,name,hobby
from t_person lateral view explode(hobbies) t_hobby as hobby

-- 炸裂函数的应用
-- 统计各个爱好的人数
select hobby,count( * )
from t_person lateral view explode(hobbies) t_hobby as hobby
group by hobby;
posexplode相比较explode会多出一列索引值
select name,`index`,hobby from t_person lateral view posexplode(hobbies) t2 as `index`,hobby

7.子查询 (嵌套查询)

-- 子查询就是将一个SQL的结果视为一个虚拟的表或者一个值
-- 在hive中,子查询可以出现在三个地方,一个是from后面,一个是where后面,还有select
-- 需要注意的是,子查询在放入到select后面时,尽可能的输出单值(单列单行)

-- 子查询结果是一行一列
select * from t_person where salary > (
  select avg(salary) from t_person 
)

-- 子查询结果是多行一列
select distinct name
from(
 select * from t_person lateral view explode(hobbies) t2 as hobby 
)t1 where t1.hobby in (
  select explode(hobbies) from t_person where name = '赵6'
) and name <> '赵6'

-- 子查询结果是多行多列,作为表使用
-- 统计有哪些爱好,并去重。
select distinct t.hobby from 
(select explode(hobbies) as hobby from t_person ) t

8.排序

# 全局排序 
语法:select * from 表 order by 字段 asc|desc;
-- 按照薪资降序排序 
select * from t_person order by salary desc;
# 局部排序(分区排序)
概念:启动多个reduceTask,对数据进行排序(预排序),局部有序。
     局部排序关键词 sort by
        默认reducetask个数只有1个,所有分区也只有一个。所以默认和全排序效果一样。
语法:select * from 表 distribute by 分区字段 sort by 字段 asc|desc;
-- 1. 开启reduce个数
-- 设置reduce个数
set mapreduce.job.reduces = 3;
-- 查看reduce个数
 set mapreduce.job.reduces;
-- 2. 使用sort by排序 +distribute by 指定分区列。
select * from t_person distribute by addr.city sort by salary desc;
-- 3.可以将查询结果写入本地磁盘,用于测试sort by的效果
insert overwrite local directory '/opt/data/sortby'
select * from t_person distribute by addr.city sort by salary desc;

9.开窗函数(分析函数、窗口函数)

开窗函数:在开窗函数出现之前存在着很多用 SQL 语句很难解决的问题,很多都要通过复杂的相关子查询或者存储过程来完成。为了解决这些问题,在 2003 年 ISO SQL 标准加入了开窗函数,开窗函数的使用使得这些经典的难题可以被轻松的解决。目前在 MSSQLServer、Oracle、DB2 等主流数据库中都提供了对开窗函数的支持,MySQL8.0支持以及hive也支持。 开窗函数简介:与聚合函数一样,开窗函数也是对行集组进行聚合计算,但是它不像普通聚合函数那样每组只返回一个值,开窗函数可以为每组返回多个值,因为开窗函数所执行聚合计算的行集组是窗口。在 ISO SQL 规定了这样的函数为开窗函数,在 Oracle 中则被称为分析函数。

1.准备数据

Tom,BeiJing,20,3000
Tim,ChengDu,21,4000
Jim,BeiJing,22,3500
Lily,London,21,2000
John,NewYork,22,1000
YaoMing,BeiJing,20,3000
Swing,London,22,2000
Guo,NewYork,20,2800
YuQian,BeiJing,24,8000
Ketty,London,25,8500
Kitty,ChengDu,25,3000
Merry,BeiJing,23,3500
Smith,ChengDu,30,3000
Bill,BeiJing,25,2000
Jerry,NewYork,24,3300

2.建表/导入数据

create table t_person2 (
    fname string,
    fcity string,
    fage int,
    fsalary int
)row format delimited
fields terminated by ','

load data local inpath '/root/kaichuang.txt' into table t_person2 ;

3.开窗函数的语法

开窗函数格式: 函数名([列]) OVER([选项])
OVER 关键字表示把函数当成开窗函数而不是聚合函数。SQL 标准允许将所有聚合函数用做开窗函数,使用 OVER 关键字来区分这两种用法。

如果 OVER 关键字后的括号中的选项为空,则开窗函数会对结果集中的所有行进行聚合运算。

PARTITION BY 子句:
开窗函数的 OVER 关键字后括号中的可以使用 PARTITION BY 子句来定义行的分区来供进行聚合计算。与 GROUP BY 子句不同,PARTITION BY 子句创建的分区是独立于结果集的,创建的分区只是供进行聚合计算的,而且不同的开窗函数所创建的分区也不互相影响

ORDER BY子句:
开窗函数中可以在OVER关键字后的选项中使用ORDER BY子句来指定排序规则,而且有的开窗函数还要求必须指定排序规则。使用ORDER BY子句可以对结果集按照指定的排序规则进行排序,并且在一个指定的范围内进行聚合运算

排序(排名、序号)开窗函数

RANK() 排序相同时会重复,总数不会变
DENSE_RANK() 排序相同时会重复,总数会减少
ROW_NUMBER() 会根据顺序计算

select 
 fname,fcity,fage,fsalary,
 ROW_NUMBER() over(order by fsalary desc) x1,
 Rank() over(order by fsalary desc) x2,
 DENSE_RANK () over(order by fsalary desc) x3
from t_person2 ;

聚合开窗函数

-- 聚合函数(列)  over(partition by 列名 order by 列名)
select 
 fname,fcity,fage,fsalary,
 max(fsalary) over(partition by fage order by fsalary desc) x1
from t_person2 ;

create table t_sales(
    name        string,
    mt          int,
    sales_num   int  
);

insert into t_sales 
values ('苹果旗舰店',1,500),('苹果旗舰店',2,100),('苹果旗舰店',3,400),('苹果旗舰店',4,500),('苹果旗舰店',5,100),
       ('华为旗舰店',1,800),('华为旗舰店',2,200),('华为旗舰店',3,400),('华为旗舰店',4,300),('华为旗舰店',5,200);

insert into t_sales 
values ('苹果旗舰店',7,500),('苹果旗舰店',6,100)      
       
-- 需求1:统计每个店铺的总销售额
select *,sum(sales_num) over(partition by shop) x1
from t_sales 

-- 需求2:统计每个店铺的累计销售额
select *,sum(sales_num) over(partition by shop order by mt) x1
from t_sales 

其他开窗函数

① lag(字段名,n,0) -- 移位开窗函数,表示返回向上第n行指定字段对应数据。其中n代表向上偏移n行,0代表若偏移行数超出表范围则返回0也可以改成其他值,若不写则默认null
create table t_student(
   name  string,
   mt    int,
   score int
)

insert into t_student values('张三',1,100),('张三',2,15),('张三',3,85),('张三',4,95),
                            ('李四',1,60),('李四',2,99),('李四',3,75),('李四',4,34)

-- 语法 lag(列名) 向上一行,找到指定列的值,如果本身就是第一行,则返回null
--    lag(列名,n,默认值)  向上n行,找到指定列的值,如果本身就是第一行,则返回默认值
select name,mt,score,lag(score) over(partition by name order by mt)
from t_student                 

select name,mt,score,lag(score,1,score) over(partition by name order by mt)
from t_student    

-- 应用场景  计算每个学员考试成绩的环比  (当前月成绩-上个月成绩)/上个月成绩*100%
select name,mt,score,round((score-x1)/x1*100,2) x2
from(
        select name,mt,score,lag(score) over(partition by name order by mt) x1
        from t_student   
)t1 where x1 is not null 

② lead(字段名,n,0) -- 移位开窗函数,与lag()相反,表示返回向下第n行指定字段对应数据
语法:lead(字段名)、lead(字段名,行号,默认值)

③ first_value(列名) -- 取分组内排序后,截止到当前行,第一个值
select name,mt,score,first_value(mt) over (partition by name order by mt) x1
from t_student;

④ last_value(列名) -- 取分组内排序后,截止到当前行,最后一个值
select name,mt,score,last_value(mt) over (partition by name order by mt) x1
from t_student;
标签: hive sql hadoop

本文转载自: https://blog.csdn.net/m0_46331650/article/details/139074148
版权归原作者 呆呆不呆~ 所有, 如有侵权,请联系我们删除。

“hive sql -- 看完就会了!”的评论:

还没有评论