笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值,找寻数据的秘密,笔者认为,数据的价值不仅仅只体现在企业中,个人也可以体会到数据的魅力,用技术力量探索行为密码,让大数据助跑每一个人,欢迎直筒们关注我的公众号,大家一起讨论数据中的那些有趣的事情。
我的公众号为:livandata
1 DDL操作(建表语句)
1.1、建表语法
1)表的创建方法:
建表:
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
说明:
1.1) CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。
1.2) EXTERNAL关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。
LOCATOION:在建外部表时指定的数据存储目录。
create external table fz_external_table(
id int,
name string,
age int,
tel string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE
LOCATION '/user/hive/external/fz_external_table';
1.3)LIKE 允许用户复制现有的表结构,但是不复制数据:
CREATE TABLE t4 like t2;
1.4)ROW FORMAT:创建表时指定的数据切分格式
DELIMITED [FIELDS TERMINATED BY char]
[COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
|SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, ...)]
用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的SerDe,Hive通过 SerDe 确定表的具体的列的数据。
SerDe是Serialize/Deserilize的简称,目的是用于序列化和反序列化
例如:
CREATE TABLE psn (
id int,
name string,
hobbies ARRAY
address MAP
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':';
参考:https://www.cnblogs.com/zkio/p/7283770.html
1.5)STORED AS:
SEQUENCEFILE|TEXTFILE|RCFILE
如果文件数据是纯文本,可以使用 STORED AS TEXTFILE:默认格式,数据不做压缩,磁盘开销大,数据解析开销大。
如果数据需要压缩,使用 STORED AS SEQUENCEFILE:支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。
RCFILE是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。
CREATE TABLE if not exists testfile_table(
site string,
url string,
pv bigint,
label string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS textfile;
LOAD DATA LOCAL INPATH '/app/weibo.txt'
OVERWRITE INTO TABLE textfile_table;
1.6)CLUSTERED BY:
对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
SORTED BY:对桶中的一个或多个列另外排序。
把表(或者分区)组织成桶(Bucket)有两个理由:
1.6.1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。
1.6.2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。
create table stu_buck(
sno int,
sname string,
sex string,
sage int,
sdept string)
clustered by(sno) sorted by(sno DESC) into 4 buckets
row format delimited fields terminated by ',';
1.7)COMMENT:可以为表与字段增加描述
1.8)PARTITIONED BY :根据分区来查看表中的内容,每个分区以文件夹的形式单独存在表文件夹的目录下。
2)具体实例:
2.1)创建内部表的三种方式:
2.1.1)第一种方式:
Create table if not exists default.weblog(
Ip string,
Time string,
Req_url string,
Status string,
Size string)
Row format delimited fields terminated by ‘\t’;
数据存储:
Load data local inpath’/opt/hive/weblog.txt’ into table default.weblog;
查看数据:
Select * from default.weblog;
2.1.2)第二种方式:
Create table default.weblog
As select ip, time, req_url, from default.weblog;
查看表结构:
Desc default.weblog;
2.1.3)第三种方式:
Create table if not exists default.weblog_s like default.weblog;
Select * from weblog;
Desc weblog;
2.2)创建外部表pageview:
Create external table if not exists pageview(
Pageid int,
Page_url string comment ‘the page url’)
Row format delimited fields terminated by ‘,’
Location ‘hdfs://192.168.11.191:9000/user/hive/warehouse/’;
2.3)创建分区表invites:
分区是指将数据放在多个单独的文件夹中,减少运行的时间;
create table student_p(
Sno int,
Sname string,
Sex string,
Sage int,
Sdept string)
partitioned by(part string)
row format delimited fields terminated by ','
stored as textfile;
2.3.1)内部分区表:
create table student(
id int,
name string)
partitioned by (cls string)
row format delimited fields terminated by '\t';
2.3.2)分区表装载数据:
load data local inpath '/home/airib/work/hadoop/book' into table student partition (cls='class2');
2.3.3)外部分区表:可以单独的往某个分区中导入数据;
create external table teacher (
id int,
name string)
partitioned by (cls string)
row format delimited fields terminated by '\t' location '/user/teacher';
location '/user/teacher'
2.4)创建带桶的表:
如何理解分桶:
对于某一个表或者分区,hive可以进一步构建成桶,是更为细粒度的划分;一开始数据都是在一起的,建造表的时候会按照id将表分在四个文件中,分别命名为1,2,3,4;数据会对应的存入到这四个文件中,数据的存取方式为将数据按照id进行hash散列,然后按照hash散列分到四个文件中。
分桶建表的基本语法为:
Create table student(
Id int,
Age int,
Name string)
Partitioned by (stat_Date string)
Clustered by (id) sorted by (age) into 2 buckets
Row format delimited fields terminated by ‘,’;
注意:
2.4.1)对于已有的数据,将数据导入到分桶的表中的时候是不主动分桶的,他只是记录了数据是分过桶的,文件没有变,因此在load数据的时候一般先分桶,再导入数据;
2.4.2)分桶处理时一般采用insert语句,分布进行,步骤如下:
首先:将数据load进入到一个普通的表中;
Create table t_p(id string, name string)
Row format delimited fields terminated by ‘,’;
其次:有一个分桶的开关需要打开:
set hive.enforce.bucketing = true;
set mapreduce.job.reduces = 4;
其三:然后将数据按照分桶原则从表中插入到分桶的表中,经历以下语句,数据就会被完整的分到四个桶中,四个桶分为四个不同的文件:
Insert into table t_buck
Select id, name from t_p distribute by (id) sort by (id);
reduce的数量需要与分桶的数量一致。
1.2、修改表
1)增加/删除分区
1.1)语法结构:
ALTER TABLE table_name
ADD [IF NOT EXISTS]
partition_spec [ LOCATION'location1' ]
partition_spec [ LOCATION 'location2' ] ...
其中partition_spec为:
PARTITION (partition_col = partition_col_value, partition_col =partiton_col_value, ...)
ALTER TABLE table_name DROP partition_spec, partition_spec,...
1.1.1)增加分区:
alter table student_p add partition(part='a') partition(part='b');
1.1.2)删除分区:
show partitions student;
alter table student_p drop partition(stat_date='20160105');
alter table student_p add partition(stat_date=’20140101’)
location ‘/user/hive/warehouse/student’ partition(stat_Date=’ 20140102’)
1.1.3)重命名表:
语法结构:
ALTER TABLE table_name RENAME TO new_table_name
具体实例:
alter table students renameto students1;
show tables;
2)增加/更新列:
2.1)语法结构:
ALTER TABLE table_name
ADD|REPLACE COLUMNS (
col_name data_type[COMMENT col_comment], ...
)
与:
ALTER TABLE table_name
CHANGE [COLUMN] col_old_name col_new_namecolumn_type
[COMMENT col_comment]
[FIRST|AFTER column_name]
注:ADD是代表新增一字段,字段位置在所有列后面(partition列前),REPLACE则是表示替换表中所有字段,Change是修改列及属性。
2.1.1)增加列:
Alter table students add columns(name1 string);
2.1.2)更新列:
Alter table students replace columns(id int, age int, name string);
3)删除列:
alter table students drop columns id;
4)修改列:
alter table students change columns salary salary double;
5)删除表:
drop table if exists employee;
6)修改桶:
alter table btest3 clustered by(name, age) sorted by(age) into10 buckets;
显示命令:
show tables
show databases
show partitions
show functions
desc extended t_name;
desc formatted table_name;
2 DML操作(数据操纵语句)
2.1、Load(复制/移动操作):
1)语法结构:
LOAD DATA [LOCAL] INPATH 'file path' [OVERWRITE] INTO
TABLE tablename
[PARTITION (partcol1=val1, partcol2=val2 ...)]
说明:
1.1)Load 操作只是单纯的复制/移动操作,将数据文件移动到 Hive 表对应的位置。
1.2)file path移动路径:
相对路径,例如:project/data1
绝对路径,例如:/user/hive/project/data1
包含模式的完整 URI,列如:hdfs://namenode:9000/user/hive/project/data1
1.3)LOCAL关键字:
如果没有指定 LOCAL 关键字,则根据inpath中的uri查找文件
如果指定了LOCAL,那么:
load 命令会去查找本地文件系统中的file path。如果发现是相对路径,则路径会被解释为相对于当前用户的当前路径。
load 命令会将file path中的文件复制到目标文件系统中。目标文件系统由表的位置属性决定。被复制的数据文件移动到表的数据对应的位置。
如果没有指定 LOCAL关键字,如果file path指向的是一个完整的URI,hive 会直接使用这个URI。否则:如果没有指定schema或者authority,Hive 会使用在hadoop配置文件中定义的schema和authority,fs.default.name指定了 Namenode的URI。
如果路径不是绝对的,Hive相对于/user/进行解释。
Hive 会将filepath中指定的文件内容移动到table(或者partition)所指定的路径中。
1.4)OVERWRITE关键字
如果使用了OVERWRITE关键字,则目标表(或者分区)中的内容会被删除,然后再将file path指向的文件/目录中的内容添加到表/分区中。
如果目标表(分区)已经有一个文件,并且文件名和file path中的文件名冲突,那么现有的文件会被新文件所替代。
1.4.1)加载相对路径数据:
Load data local inpath ‘buckets.txt’ into table student partition(stat_Date=’20130202’);
Dfs -ls /user/hive/warehouse/student/stat_date=20130202
1.4.2)加载绝对路径数据:
Load data local inpath ‘/root/app/datafile/buckets.txt’ into table student partition(stat_Date=’20130202’);
Dfs -ls /user/hive/warehouse/student/stat_date=20130202;
1.4.3)加载包含模式的完整url:
Load data local inpath ‘http://192.168.22.22:9000/root/app/datafile/buckets.txt’ into table student partition(stat_Date=’20130202’);
Dfs -ls /user/hive/warehouse/student/stat_date=20130202;
1.4.4)OVERWRITE关键字使用:
Load data local inpath ‘buckets.txt’ overwrite into table student partition(stat_Date=’20130202’);
Dfs -ls /user/hive/warehouse/student/stat_date=20130202;
2.2、Insert(插入语句):将查询结果插入Hive表
1)语法结构:
1.1)Base insert:
INSERT OVERWRITE TABLE tablename1
[PARTITION (partcol1=val1, partcol2=val2 ...)]
SELECT select_statement1
FROM from_statement
1.2)Multiple inserts:
FROM from_statement
INSERT OVERWRITE TABLE tablename1
[PARTITION (partcol1=val1, partcol2=val2 ...)]
SELECT select_statement1
[INSERT OVERWRITE TABLE tablename2
[PARTITION ...]
SELECT select_statement2] ...
1.3)Dynamic partition inserts:
INSERT OVERWRITE TABLE tablename
PARTITION (partcol1[=val1], partcol2[=val2] ...)
SELECT select_statement
FROM from_statement
2)具体案例:
2.1)追加数据:insert into是指后面追加内容,原有的内容不删除;
insert into table account1 select * from account_tmp;
2.2)覆盖数据:覆盖原有的内容;
insert overwrite table account1 select * from account_tmp;
2.3)多插入模式:
From student
Insert overwrite table student partition(stat_date=’20140202’)
Select id, age, name, where stat_date=’20130202’
Insert overwrite table student partition(stat_date=’20140203’)
Select id, age, name, where stat_date=’20130203’
2.4)动态分区模式:
Insert overwrite table student1 partition(stat_date)
Select id, age, name, stat_date from student where stat_date=’20140203’
3) 导出表数据:
3.1)Base insert:
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
SELECT ... FROM ...
3.1)multiple inserts:
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
SELECT select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2
SELECT select_statement2]...
4)具体实例:
4.1)导出文件到本地:
Insert overwrite local directory ‘/root/app/datafile/student1’
Select * from student1
说明:数据写入到文件系统时进行文本序列化,且每列用^A来区分,\n为换行符。用more命令查看时不容易看出分割符,可以使用: sed -e 's/\x01/|/g' filename来查看。
4.2)导出数据到HDFS:
Insert overwrite directory ‘hdfs://192.168.122.11:9000/user/hive/warehouse/mystudent’
Select * from student1;
Dfs -ls /user/hive/warehouse/mystudent;
注意:
insert...select:一般是表对表。
往表中导入数据时,查询的字段个数必须和目标的字段个数相同,不能多,也不能少,否则会报错。但是如果字段的类型不一致的话,则会使用null值填充,不会报错。
load data:一般是将外部文件放到hive中。
形式往hive表中装载数据时,则不会检查。如果字段多了则会丢弃,少了则会null值填充。同样如果字段类型不一致,也是使用null值填充。
2.3、SELECT:
1)语法结构:
SELECT [ALL | DISTINCT]
select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[CLUSTER BY col_list|[DISTRIBUTE BY col_list] [SORT BY| ORDER BY col_list]]
[LIMIT number]
注:
1.1)order by:会对输入做全局排序,因此只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
1.2)sort by:不是全局排序,其在数据进入reducer前完成排序。因此,如果用sort by进行排序,并且设置mapred.reduce.tasks>1,则sort by只保证每个reducer的输出有序,不保证全局有序。
1.3)distribute by(字段):根据指定的字段将数据分到不同的reducer,且分发算法是hash散列。
1.4)cluster by(字段):除了具有Distribute by的功能外,还会对该字段进行排序。
如果分桶和sort字段是同一个时,此时:cluster by = distribute by + sort by
分桶表的作用:最大的作用是用来提高join操作的效率;
(思考这个问题:select a.id, a.name, b.addr from a join b on a.id = b.id;
如果a表和b表已经是分桶表,而且分桶的字段是id字段
做这个join操作时,还需要全表做笛卡尔积吗?)
保存select查询结果的几种方式:
1.5)将查询结果保存到一张新的hive表中:
Create table t_tmp
As
Select * from t_p;
1.6)将查询结果保存到一张已经存在的hive表中:
Insert into table t_tmp
Select * from t_p;
1.7)将查询结果保存到指定的文件目录中(可以是本地,也可以是hdfs):
Insert into local directory ‘/home/Hadoop/test’
Select * from t_p;
2) 具体实例:
2.1)获取年龄大的3个学生:
Select id, age, name
from student
where stat_date=’20140203’
order by age desc
limit 3;
2.2)查询学生信息按年龄,降序排序:
Order by:全局排序,生成一个reducer;
Sort by:分区内排序,可生成多个reducer;
Eg:
Set mapred.reduce.tasks=4;
Select * from student sort by age desc;
2.3)按学生名称汇总学生年龄:
Select name, sum(age) from student group by name;
2.4)分区划分查询:
Distribute by:按照指定的字段或表达式对数据进行划分,输出到对应的reduce或者文件中;
cluster by:区内排序,如果distribute by,sort by使用的两个字段相同时:cluster by=distribute by+sort by功能叠加;
set mapred.reduce.tasks=2;
insert overwrite local directory 'tmp/lxw1234/'
select id from lxw1234_com
distribute by id;
上面会生成两个文件;
set mapred.reduce.tasks=2;
insert overwrite local directory 'tmp/lxw1234/'
select id from lxw1234_com
cluster by id;
上面会排序;
2.5)子查询:必须设置别名
select * from (select a+b as col form t1) t2;
2.6)where中的子查询:
left semi join语句用来替代exists/in子句:
在hive中下面的语句是无法使用的:
select * from A where A.a in (select foo from B);
select * from A where A.a exists (select foo from B where A.x=B.x);
需要使用left semi join子句:
select * from A left semi join B on(A.key=B.key);
2.7)将子查询作为一个表:hive可以通过with查询来提高查询性能,因为先通过with语法将数据查询到内存,然后后面其它查询可以直接使用。
with q1 as (select * from A where x>65)
from q1
insert overwrite table q2
select *;
2.8)虚拟列:
input_file_name:数据对应的HDFS文件;
block_offset_inside_file:该行记录在文件中的偏移量;
select id, input_file_name, block_offset_inside_file from lxm1234_com;
2.4、Hive Join:
1)语法结构:
join_table:
table_reference JOIN table_factor [join_condition]
| table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition
| table_reference LEFT SEMIJOIN table_reference join_condition
Hive支持等值连接(equalityjoins)\外连接(outer joins)和左右连接(left/rightjoins)。
Hive不支持非等值的连接,因为非等值连接非常难转化到 map/reduce 任务。
另外,Hive支持多于2个表的连接,缓存前面的表,拿最后一个表逐行进行join。
2)join注意几个关键点:
2.1)只支持等值join:
例如:
SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department =b.department)
是正确的,然而:
SELECT a.* FROM a JOIN b ON (a.id>b.id)
是错误的。
2.2)可以 join 多于2个表:
例如:
SELECT a.val,b.val, c.val
FROM a JOIN b
ON (a.key =b.key1) JOIN c ON (c.key = b.key2)
如果join中多个表的join key是同一个,则join会被转化为单个map/reduce 任务,例如:
SELECT a.val,b.val, c.val
FROM a JOIN b
ON (a.key =b.key1) JOIN c ON (c.key =b.key1)
被转化为单个map/reduce任务,因为join中只使用了b.key1作为join key。
SELECT a.val, b.val, c.val
FROM a JOIN b
ON (a.key =b.key1) JOIN c ON(c.key = b.key2)
而这一join 被转化为2个map/reduce任务。因为b.key1用于第一次join 条件,而b.key2用于第二次join。
2.3)join 时,每次 map/reduce 任务的逻辑如下:
reducer会缓存join序列中除了最后一个表的所有表的记录,再通过最后一个表将结果序列化到文件系统。这一实现有助于在reduce端减少内存的使用量。实践中,应该把最大的那个表写在最后(否则会因为缓存浪费大量内存)。
例如:
SELECT a.val, b.val, c.val
FROM a JOIN b
ON(a.key = b.key1) JOIN c ON (c.key = b.key1)
所有表都使用同一个join key(使用 1 次 map/reduce 任务计算)。Reduce 端会缓存a表和b表的记录,然后每次取得一个c表的记录就计算一次join 结果,类似的还有:
SELECT a.val,b.val, c.val
FROM a JOIN b
ON(a.key = b.key1) JOIN c ON (c.key = b.key2)
这里用了2次map/reduce任务。第一次缓存a表,用b表序列化;第二次缓存第一次 map/reduce 任务的结果,然后用c表序列化。
2.4)LEFT,RIGHT和FULL OUTER关键字用于处理join中空记录的情况:
例如:
SELECT a.val, b.val
FROM a LEFT OUTER JOIN b
ON (a.key=b.key)
对应所有a表中的记录都有一条记录输出。输出的结果应该是a.val,b.val,当 a.key=b.key时,而当b.key中找不到等值的a.key记录时也会输出:
a.val, NULL
所以 a 表中的所有记录都被保留了;
SELECT A.val, B.val
FROM A RIGHT OUTER JOIN B
ON(A.key=B.key);
会保留所有b表的记录。
2.5)Join 发生在 WHERE 子句之前:
如果你想限制join的输出,应该在WHERE子句中写过滤条件——或是在join 子句中写。这里面一个容易混淆的问题是表分区的情况:
SELECT a.val,b.val
FROM a LEFT OUTER JOIN b
ON (a.key=b.key)
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'
上例会join a表到b表(OUTER JOIN),列出a.val和b.val的记录。WHERE 从句中可以使用其他列作为过滤条件。但是,如前所述,如果 b 表中找不到对应 a 表的记录,b 表的所有列都会列出 NULL,包括 ds 列。也就是说,join 会过滤 b 表中不能找到匹配a表join key的所有记录。这样的话,LEFT OUTER就使得查询结果与WHERE子句无关了。解决的办法是在OUTER JOIN时使用以下语法:
SELECT a.val, b.val
FROM a LEFT OUTER JOIN b
ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07')
这一查询的结果是预先在join阶段过滤过的,所以不会存在上述问题。这一逻辑也可以应用于RIGHT和FULL类型的join中。
2.6)Join 是不能交换位置的:
无论是LEFT还是RIGHT join,都是左连接的。
SELECT a.val1,a.val2, b.val, c.val
FROM a JOIN b ON(a.key = b.key)
LEFT OUTER JOIN c ON (a.key = c.key)
先join a表到b表,丢弃掉所有join key中不匹配的记录,然后用这一中间结果和c表做join。这一表述有一个不太明显的问题,就是当一个key在a表和c表都存在,但是b表中不存在的时候:整个记录在第一次join,即a JOIN b的时候都被丢掉了(包括a.val1,a.val2和a.key),然后我们再和c 表 join的时候,如果c.key与a.key或b.key相等,就会得到这样的结果:NULL, NULL, NULL, c.val
2.7)内连接inner join,只返回满足条件的结果:
SELECT t.dept, e.name
FROM employees e INNER JOIN dept t
ON e.deptno=t.deptno;
2.8)查询带桶的内容:
SELECT *
FROM bucketed_user
TABLESAMPLE(bucket 1 out of 2 on id)
WHERE day='20180703';
语法:
tablesample(bucket x out of y):桶抽样
y必须是table总bucket数的因子或者倍数。hive根据y的大小决定抽样的比例。
例如:table共有64份,当y=32时,抽取(64/32)个bucket,即两个,当y=128时,抽取(64/128)=1/2个桶的数据;
x表示从哪个桶开始抽数据。
例如:table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16)=2个bucket的数据,分别为第3个bucket和第3+16=19个bucket的数据;
2.5、update:
1)hive中的update语句会有一定的限制:
1.1)必须带有分桶属性(buckets);
1.2)需要指定orc file format和acid output format格式;
1.3)建表时必须指定参数(‘transactional’=true);
1.4)必须首先修改hive-site.xml中的内容;
2)其次:
Create table student(
id int,
name string)
clustered by(name) into 2 buckets
stored as orc tblproperties('transactional'='true');
3)其三:
update student set id='444'
where name='tom';
2.6、delete:
1)删除表:
Drop table if exists students;
2)删除表中所有内容:
Truncate table employees;
3)删除表中部分数据:
Insert overwrite table table1 select * from table1 where XXXX;
XXXX是表中需要保留的数据;
4)具体实例:
4.1)获取已经分配班级的学生姓名:
SELECT name, classname
FROM student a join class b ON(a.name=b.std_name);
4.2)获取尚未分配班级的学生姓名:
SELECT name, classname
FROM student a left join class b ON (a.name=b.std_name)
WHERE b.std_name is null;
4.3)LEFT SEMI JOIN是IN/EXISTS的高效实现:
SELECT id, name
FROM student a LEFT SEMI JOIN class b ON (a.name=b.std_name);
3 Hive的sql案例:
3.1、查询全体学生的学号与姓名:
hive>select Sno,Sname from student;
3.2、查询选修了课程的学生姓名:
hive>select distinct Sname from student inner join sc on student.Sno=Sc.Sno;
----hive的group by 和集合函数
3.3、查询学生的总人数:
hive>select count(distinct Sno)count from student;
3.4、计算1号课程的学生平均成绩
hive>select avg(distinct Grade) from sc where Cno=1;
3.5、查询各科成绩平均分
hive> select Cno,avg(Grade) from sc group by Cno;
3.6、查询选修1号课程的学生最高分数:
select Grade from sc where Cno=1 sort by Grade desc limit 1;
(注意比较:select * from sc where Cno=1 sort by Grade
select Grade from sc where Cno=1 order by Grade)
3.7、求各个课程号及相应的选课人数:
hive>select Cno,count(1) from sc group by Cno;
3.8、查询选修了3门以上的课程的学生学号
hive>select Sno from (select Sno,count(Cno) CountCno from sc group by Sno)a wherea.CountCno>3;
或:
hive>select Sno from sc group by Sno having count(Cno)>3;
----hive的Order By/Sort By/Distribute By
Order By:在strict 模式下(hive.mapred.mode=strict),orderby 语句必须跟着limit语句,但是在nonstrict下就不是必须的,这样做的理由是必须有一个reduce对最终的结果进行排序,如果最后输出的行数过多,一个reduce需要花费很长的时间。
3.9、查询学生信息,结果按学号全局有序:
hive>set hive.mapred.mode=strict; <默认nonstrict>
hive> select Sno from student order by Sno;
FAILED: Error in semantic analysis: 1:33 In strict mode, if ORDER BYis specified, LIMIT must also be specified. Error encountered near token 'Sno'
Sort By:它通常发生在每一个redcue里,“order by” 和“sort by"的区别在于,前者能给保证输出都是有顺序的,而后者如果有多个reduce的时候只是保证了输出的部分有序。set mapred.reduce.tasks=
此方法会根据性别划分到不同的reduce中,然后按年龄排序并输出到不同的文件中。
3.10、查询学生信息,按性别分区,在分区内按年龄有序
hive>set mapred.reduce.tasks=2;
hive>insert overwrite local directory '/home/hadoop/out'
select * from student distribute by Sex sort by Sage;
----Join查询,join只支持等值连接
3.11、查询每个学生及其选修课程的情况
hive>select student.*,sc.* from student join sc on (student.Sno =sc.Sno);
3.12、查询学生的得分情况。
hive>selectstudent.Sname,course.Cname,sc.Grade from student join sc on student.Sno=sc.Snojoin course on sc.cno=course.cno;
3.13、查询选修2号课程且成绩在90分以上的所有学生。
hive>select student.Sname,sc.Grade from student join sc on student.Sno=sc.Sno
where sc.Cno=2 and sc.Grade>90;
----LEFT,RIGHT 和 FULL OUTER JOIN ,inner join, left semi join
3.14、查询所有学生的信息,如果在成绩表中有成绩,则输出成绩表中的课程号
hive>select student.Sname,sc.Cno from student left outer join sc onstudent.Sno=sc.Sno;
如果student的sno值对应的sc在中没有值,则会输出student.Snamenull.如果用right out join会保留右边的值,左边的为null。
Join 发生在WHERE 子句之前。如果你想限制join 的输出,应该在 WHERE 子句中写过滤条件——或是在join 子句中写。
----LEFT SEMI JOIN:Hive 当前没有实现IN/EXISTS 子查询,可以用 LEFT SEMI JOIN 重写子查询语句
重写以下子查询为LEFT SEMI JOIN:
SELECT a.key, a.value FROM a WHERE a.key exist in (SELECTb.key FROM B);
可以被重写为:
SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key)
3.15、查询与“刘晨”在同一个系学习的学生:
hive>select s1.Sname from student s1 left semi join student s2 on s1.Sdept=s2.Sdeptand s2.Sname='刘晨';
注意比较:
select *
from student s1 left join student s2 on s1.Sdept=s2.Sdept and s2.Sname='刘晨';
select *
from student s1 right join student s2 on s1.Sdept=s2.Sdept and s2.Sname='刘晨';
select *
from student s1 inner join student s2 on s1.Sdept=s2.Sdept and s2.Sname='刘晨';
select *
from student s1 left semi join student s2 ons1.Sdept=s2.Sdept and s2.Sname='刘晨';
select s1.Sname
from student s1 right semi join student s2 ons1.Sdept=s2.Sdept and s2.Sname='刘晨';
以上为常用的HQL的基本语法,如有补充后续会继续跟进。