HiveSQL部分语法

152 阅读8分钟

内部表与外部表

CREATE TABLE... 表示创建的是内部表

内部表

 -- 内部表
 CREATE table if not exists stu(id int,name string);
 ​
 INSERT INTO STU values(1,"陈平安"),(2,"宁姚");
 ​
 SELECT * FROM STU;
 ​
 -- 自行指定列之间的分隔符
 CREATE table if not exists stu2(id int,name string)
 row format delimited fields terminated by '\t';             -- 固定写法,略显臭长
 ​
 INSERT INTO STU2 values(1,"陈平安"),(2,"宁姚");
 ​
 SELECT * FROM STU2;
 ​
 -- 查看表类型和详情
 desc formatted stu2 ;
 MANAGED_TABLE       -- 表示内部表
 ​
 -- 删除表后,表关系和数据均被删除
 DROP table stu2;

外部表

CREATE external table...

external:表示创建的是外部表

1、先创建外部表,然后移动数据
 -- 1、先创建外部表,然后移动数据
 -- 建表
 --      必须使用row format delimited fields terminated by指定列分隔符(分隔符是为了与数据保持一致)
 --      必须使用LOCATION指定数据路径
 CREATE external table test_ext1(id int,name string)
 row format delimited fields terminated by '\t' 
 LOCATION '/tmp/test_ext1/';
 ​
 -- 本地手动创建数据,需要注意数据的分隔符需要与建表时设置的分隔符保持一致
 -- 上传本地数据至 hdfs 的 /tmp/test_ext1/ 目录下
  
 -- 数据上传成功后,表、数据均存在,即可查询验证,看到数据结果
 SELECT * FROM test_ext1 ;
 ​
 -- 查看表类型和详情
 desc formatted test_ext1 ;
 EXTERNAL_TABLE       -- 表示外部表
2、先上传数据,后创建外部表
 -- 2、先上传数据,后创建外部表
 -- 本地手动创建数据,需要注意数据的分隔符需要与建表时设置的分隔符保持一致
 -- 上传本地数据至 hdfs 的 /tmp/test_ext2/ 目录下
 ​
 -- 建表
 CREATE external table test_ext2(id int,name string)
 row format delimited fields terminated by '\t' 
 LOCATION '/tmp/test_ext2/';
 ​
 -- 建表成功后,表、数据均存在,即可查询验证,看到数据结果
 SELECT * FROM test_ext2 ;
 ​
 -- 查看表类型和详情
 desc formatted test_ext1 ;
 EXTERNAL_TABLE       -- 表示外部表
 ​
 -- 删除表后,hdfs处数据文件不会被删除,删除的只是表关系,物理层面不受影响
 DROP table test_ext2;

内部表与外部表的相互转换

 -- 内部表与外部表之间的转换
 -- 'EXTERNAL' = 'TRUE' 为固定写法,必须大写,不可更改
 desc formatted stu ;
 desc formatted test_ext1 ;
 ​
 ALTER table stu set TBLPROPERTIES ('EXTERNAL' = 'TRUE');
 ALTER table test_ext1 set TBLPROPERTIES ('EXTERNAL' = 'FALSE');

数据加载

1、LOAD 语法

 -- 1、LOAD语法
 -- 建表
 CREATE TABLE test_load(
     dt STRING comment '时间(时分秒)',
     user_id STRING comment '用户ID',
     word STRING comment '搜索词',
     url STRING comment '用户访问网址'
 ) comment '搜索引擎日志表' 
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
 ​
 -- 加载数据
 -- 从本地加载数据,数据不移动
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/search_log.txt' INTO TABLE myhive.test_load;
 ​
 -- 从 hdfs 加载数据,数据本身是被移动的
 LOAD DATA INPATH '/tmp/search_log.txt' INTO TABLE MYHIVE.TEST_LOAD ;
 ​
 -- OVERWRITE,加载数据时,覆盖已存在数据
 LOAD DATA INPATH '/tmp/search_log.txt' OVERWRITE INTO TABLE MYHIVE.TEST_LOAD ;
 ​
 SELECT * FROM test_load ;

2、INSERT INTO 语法

 -- 2、INSERT INTO 语法
 -- 建表
 CREATE TABLE test_load2(
     dt STRING comment '时间(时分秒)',
     user_id STRING comment '用户ID',
     word STRING comment '搜索词',
     url STRING comment '用户访问网址'
 ) comment '搜索引擎日志表' 
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
 ​
 -- INTO 是追加模式
 INSERT INTO TABLE TEST_LOAD2 
 SELECT * FROM TEST_LOAD ;
 ​
 -- OVERWRITE 是覆盖模式
 INSERT OVERWRITE TABLE TEST_LOAD2 
 SELECT * FROM TEST_LOAD ;
 ​
 SELECT * FROM TEST_LOAD2 TL ;

数据导出

1、INSERT OVERWRITE 方式

 -- 1、INSERT OVERWRITE 方式
 -- 将查询结果导出到本地 - 使用默认分隔符
 INSERT OVERWRITE LOCAL directory '/home/hadoop/tmpdata/'
 SELECT * FROM TEST_LOAD ;
 ​
 -- 查询的结果导出到本地 - 指定列分隔符
 INSERT OVERWRITE LOCAL directory '/home/hadoop/tmpdata/'
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
 SELECT * FROM TEST_LOAD ;
 ​
 -- 将查询的结果导出到HDFS上(不带local关键字)
 INSERT OVERWRITE directory '/tmp/export/' 
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
 SELECT * FROM TEST_LOAD ;

2、hive shell 方式

 -- 2、hive shell 方式
 -- > 表重定向,将输出结果重定向到 目标文件中
 ​
 -- "-e"表示执行 字符串中的sql语句
 bin/hive -e "select * from myhive.test_load;" > /home/hadoop/export3/export4.txt
 ​
 -- "-f"表示执行 指定的sql文件
 bin/hive -f export.sql > /home/hadoop/export4/export4.txt

分区表

partitioned by (month STRING,...)

month STRING:指定的分区列,分区类型,可以有多个

单分区表

 -- 创建 单分区表 ,分区按月分区
 CREATE TABLE score(
     id STRING,
     cid STRING ,
     score STRING 
 )
 partitioned by (month STRING)
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
 ​
 -- 加载数据到分区表
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/score.txt' INTO TABLE MYHIVE.SCORE partition (month = '202408');
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/score.txt' INTO TABLE MYHIVE.SCORE partition (month = '202407');
 ​
 SELECT * FROM SCORE S ;

多分区表

 -- 创建 多分区表 ,分区层次:年、月、日
 CREATE TABLE score2(
     id STRING,
     cid STRING ,
     score STRING 
 )
 partitioned by (year STRING , month STRING , day STRING)
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
 ​
 -- 加载数据到分区表
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/score.txt' 
 INTO TABLE MYHIVE.SCORE2 
 partition (year = '2024' , month = '08' , day = '05');
 ​
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/score.txt' 
 INTO TABLE MYHIVE.SCORE2 
 partition (year = '2024' , month = '08' , day = '06');
 ​
 SELECT * FROM SCORE2 S ;

分桶表

clustered by (c_id) c_id:指定的分桶字段

INTO 3 buckets 3:指定的分桶数量

  • 问:为什么只能使用 INSERT INTO 方法加载数据?
  • 答:需要使用 INSERT INTO 触发 MapReduce 进行 hash 取模运算,基于分桶列的值,确定哪一条数据进入哪一个桶文件中。
 -- 开启分桶的自动优化
 set hive.enforce.bucketing=true;
 -- 创建分桶表
 CREATE TABLE course(
     c_id STRING,
     c_name STRING ,
     t_id STRING 
 )
 clustered by (c_id)
 INTO 3 buckets
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
 ​
 -- 加载数据
 -- 1、创建临时中转表
 CREATE TABLE course_tmp(
     c_id STRING,
     c_name STRING ,
     t_id STRING 
 )
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
 ​
 -- 2、向中转表 load data 数据
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/course.txt' INTO TABLE MYHIVE.COURSE_TMP ;
 ​
 SELECT * FROM COURSE_TMP ;
 ​
 -- 3、从中转表进行 insert select 向分桶表加载数据
 INSERT INTO TABLE COURSE 
 SELECT * FROM COURSE_TMP cluster by (c_id);
 ​
 SELECT * FROM COURSE ;

复杂数据类型

Array

COLLECTION ITEMS TERMINATED BY ',';

‘,’:表示array值之间的分隔符是 ,

 -- 创建一个 array 测试表
 CREATE TABLE test_array (
     name STRING,
     work_locations array<STRING > 
 )
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
 COLLECTION ITEMS TERMINATED BY ',';
 ​
 -- 加载数据
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/data_for_array_type.txt' 
 INTO TABLE test_array ;
 ​
 -- 查询所有数据
 SELECT * FROM test_array ;

函数

  • 数组[数字序号]:可以取出指定需要元素(从0开始)
  • size(数组):可以统计数组元素个数
  • array_contains(数组, 数据):可以查看指定数据是否在数组中存在
 -- 查询loction数组中第一个元素
 SELECT name,work_locations [4]
 FROM test_array ;
 ​
 -- 查询location数组中元素的个数
 SELECT name,SIZE (work_locations)
 FROM test_array ;
 ​
 -- 查询location数组中包含tianjin的信息 
 SELECT *
 FROM test_array 
 WHERE ARRAY_CONTAINS(work_locations, 'tianjin');

Map

COLLECTION ITEMS TERMINATED BY '#';

‘#':表示array值之间的分隔符是 #

MAP KEYS TERMINATED BY ':';

':':表示键与值之间的分隔符是 :

 -- 建表
 CREATE TABLE test_map(
     id INT,
     name STRING,
     members map<STRING ,STRING >,
     age INT 
 )
 ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
 COLLECTION ITEMS TERMINATED BY '#'
 MAP KEYS TERMINATED BY ':';
 ​
 -- 加载数据
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/data_for_map_type.txt' 
 INTO TABLE TEST_MAP ;
 ​
 -- 查询全部
 SELECT * FROM TEST_MAP TM ;

函数

  • map[key]:获取指定key的值
  • map_keys(map):取到全部的key作为array返回,map_values(map)取到全部values
  • size(map):统计K-V对的个数
  • array_contains(map_values(map), 数据) :统计map是否包含指定数据
 -- 查询father、mother这两个map的key
 SELECT id,name,MEMBERS['father'] father,MEMBERS['mother'] mother ,AGE FROM TEST_MAP TM ;
 ​
 -- 查询全部map的key,使用map_keys函数,结果是array类型
 SELECT *,map_keys(MEMBERS) FROM TEST_MAP TM ;
 ​
 -- 查询全部map的value,使用map_values函数,结果是array类型
 SELECT *,map_values (MEMBERS) FROM TEST_MAP TM ;
 ​
 -- 查询map类型的KV对数量
 SELECT *, SIZE(MEMBERS) FROM TEST_MAP TM ;
 ​
 -- 查询map的key中有brother的数据
 SELECT * FROM TEST_MAP
 WHERE ARRAY_CONTAINS(map_keys(MEMBERS),'brother') ;

Struct

COLLECTION ITEMS TERMINATED BY ':';

':':表示strcut各个数据之间的分隔符是 :

 drop table TEST_STRUCT ;
 -- 建表
 CREATE TABLE test_struct(
     id STRING ,
     info struct<name:STRING ,age:INT>
 )
 ROW FORMAT DELIMITED FIELDS TERMINATED BY '#'
 COLLECTION ITEMS TERMINATED BY ':';
 ​
 -- 加载数据
 LOAD DATA LOCAL INPATH '/home/hadoop/tmpdata/data_for_struct_type.txt' 
 INTO TABLE TEST_STRUCT ;
 ​
 -- 查询全部
 SELECT * FROM TEST_STRUCT TS ;
 ​
 -- 直接使用列名.子列名 即可从struct中取出子列查询
 SELECT id, info.name, info.age FROM TEST_STRUCT TS ;

Sampling采样

1、基于随机分桶抽样

SELECT ... FROM tbl TABLESAMPLE(BUCKET x OUT OF y ON(colname | rand()))

  • x表示从y里面随机抽取x份数据作为取样
  • y表示将表数据随机划分成y份(y个桶)
  • 使用colname作为随机依据,则其它条件不变下,每次抽样结果一致
  • 使用rand()作为随机依据,每次抽样结果都不同
 # 根据 ORDERID列,分成 10 桶, 取 2 桶
 SELECT * 
 FROM ORDERS
 TABLESAMPLE(BUCKET 2 OUT  OF 10 ON ORDERID);
 ​
 # 随机分成 10 桶,随机取 2 桶
 SELECT * 
 FROM ORDERS
 TABLESAMPLE(BUCKET 2 OUT  OF 10 ON rand());

2、基于数据块抽样

SELECT ... FROM tbl TABLESAMPLE(num ROWS | num PERCENT | num(K|M|G));

  • num ROWS 表示抽样num条数据
  • num PERCENT 表示抽样num百分百比例的数据
  • num(K|M|G) 表示抽取num大小的数据,单位可以是K、M、G表示KB、MB、GB
 # 按表中数据顺序,取前 10条 数据
 SELECT * 
 FROM ORDERS
 TABLESAMPLE(10 ROWS);
 ​
 # 按表中数据顺序,取前 1% 数据
 SELECT * 
 FROM ORDERS
 TABLESAMPLE(1 PERCENT);
 ​
 # 按表中数据顺序,取前 1K大小 数据
 SELECT * 
 FROM ORDERS
 TABLESAMPLE(1K);
 ​
 # 按表中数据顺序,取前 1M大小 数据
 SELECT * 
 FROM ORDERS
 TABLESAMPLE(1M);

常用函数

内置函数

 -- 使用show functions查看当下可用的所有函数
 show functions
 ​
 -- 通过describe function extended funcname来查看函数的使用方式
 describe function extended funcname
 ​
 -- 取整函数: round  返回double类型的整数值部分 (遵循四舍五入)
 select round(3.1415926);
 ​
 -- 指定精度取整函数
 round(double a, int d) 
 select round(3.1415926,4);
 ​
 -- 取随机数函数: rand 每次执行都不一样 返回一个0到1范围内的随机数
 select rand();
 ​
 -- 指定种子取随机数函数,得到一个稳定的随机数序列
 rand(int seed) 
 select rand(3);
 ​
 -- 求数字的绝对值
 select abs(-3);
**```**