数据分析_HiveSQL查询语句

Hive 数据类型

基本数据类型

数据类型 长度 例子
tinyint 1byte有符号整数 20
smallint 2byte有符号整数 20
int 4byte有符号整数 20
bigint 8byte有符号整数 20
boolean 布尔类型,true或者false TRUE
float 单精度浮点数 3.14159
double 双精度浮点数 3.14159
string 字符序列。可以指定字符集。可以使用单引号或者双引号 ‘now is the time’,’for all good men’
timestamp 整数,浮点数或者字符串 1327882394(UNIX新纪元秒),1327882394.123456789(UNIX新纪元秒并跟随纳秒数)和’2016-03-13 16:23:30.123456789’(JDBC所兼容的java.sql.Timestamp时间格式)
binary 字节数组 请看后面的讨论

注:Hive会隐式地将类型转换为两个整型类型中值较大的那个类型;

集合数据类型

数据类型 描述 字面语法示例
struct 如果某个列的数据定义是struct{first String, last String}
取数方式:struct.first
struct('John', 'Doe')
map 一组“键值对”元组集合
取数方式:map['first']
map('first', 'John','last' , 'Doe')
array 每个元素都有一个编号,编号从零开始
取数方式:array[0]
array('John', 'Doe')

示例(用类似JSON的结构描述):

{
    "names": ["Smith" , "Jones"] ,   //列表Array, names[1]="Jones"
    "deductions": {                  //键值Map, deductions[’Federal’]=0.2
        "Federal": 0.2 ,
        "State": 0.05,
        "Insurance": 0.1
    }
    "address": {                     //结构Struct, address.city=”Chicago”
        "street": "1 Michigan Ave." ,
        "city": "Chicago" ,
        "state": "IL" ,
        "zip": 60600
    }
}

在Hive中实际存储形式:

Smith_Jones,Federal:0.2_State:0.05_Insurance:0.1,Michigan Ave._Chicago_1L_60600
Jan_Ketty,Federal:0.2_State Taxes:0.05_Insurance:0.1,Guang dong._China_0.5L_60661

注:MAP,STRUCT和ARRAY里的元素间关系都可以用同一个字符表示,这里用“_”

取数:

select names[1], deductions['Federal'],address.city
from learn.employees;
------
OK
Jones     0.2    Chicago
Ketty    0.2    China
Time taken: 0.123 seconds, Fetched: 2 row(s)

文本文件数据编码

Hive中默认的记录和字段分隔符

分隔符 名称 说明
\n 换行符 对于文本文件而言,每一行是一条记录,因此换行符可以分割数据。
^A <Ctrl>+A 常用于分隔列,在CREATE TABLE语句中可以使用八进制编码\001 表示。
^B <Ctrl>+B 常用于分隔ARRAY与STRUCT元素,或用于MAP中键值对之间的分隔。CREATE TABLE语句中可以使用八进制编码\002 表示
^C <Ctrl+C> MAP中键值对的分隔。CREATE TABLE语句中可以使用八进制编码\003 表示
\t 制表符 常用
逗号 常用

在创建表格的时候,可规定分隔符:

create table employee(
name            string,
salary          float,
subordinates    array<string>,
deductions      map<string, float>,
address         struct<street:string, city:string, state:string, zip:int>
)
row format delimited
fields terminated by '\001'    //列分隔符
collection items terminated by '\002'               //集合元素间的分隔符
map keys terminated by '\003'                      //map 键值对的分隔符
lines terminated by '\n'                        //行与行之间的分隔符,只支持'\n'
stored as textfile;        

读时模式

Hive处理的数据是大数据,在保存表数据时不对数据进行校验,而是在读数据时校验,不符合格式的数据设置为NULL

读时模式的优点是,加载数据库快。

HiveQL:数据定义

Hive不支持行级插入操作、更新操作和删除操作,Hive也不支持事务。
HiveQL数据定义语言部分,用于创建、修改和删除数据库、表、试图、函数和索引

Hive中的数据库

创建数据库:

create database financials;

防止因“已存在”而抛出错误:

create database if not exits financials;

查看包含的数据库:

show databases;
---
default
financials

使用正则表达式匹配:

show databases like 'h.*';
---
human_resources

存储位置:
Hive会为每个数据库创建一个目录。数据库中的表将会以这个数据库目录子目录的形式存储。数据库所在目录位于属性hive.metastore.warehouse.dir所指定的顶层目录之后。可通过如下命令修改:

hive> create database financials
    > location '/my/preferred/directory'

描述信息:

hive> create database financials
    > comment 'Holds all financial tables'

hive> describe database financials;
---
financials Holds all financial tables
  hdfs://master-server/user/hive/warehouse/financials.db

设置为当前的工作数据库

hive> use financials;

显示正在使用的数据库

hive> set hive.cli.print.current.db=true;

hive (financials)> use default;

hive (default)> set hive.cli.print.current.db=false;

hive> ...

删除数据库

hive> drop database if exists financials;  //if exists可选,避免抛出警告

注:默认情况下,Hive是不允许用户删除一个包含有表的数据库的;要么先删表,再删库;要么加上关键字 cascade

hive> drop database if exists financials cascade;

修改数据库
使用 alter database命令为某个数据库的dbproperties设置键-值对属性,来描述这个数据库的属性信息。其他信息不可更改。

hive> alter database financials set dbproperties ('edited-by' = 'Joe Dba')

创建表

在mydb库中增加employees表:
create table if not exists mydb.employees(
    name              string                comment    'employee name'//comment 后面是属性
    salary            float                 comment    'employee salary'
    subordinates      array<string>         comment  'names of subordinates'
    deductions        map<string, float>    comment   'names,values'
    address           struct<street:string, city:string, state:string, zip:int> comment 'home address'
)
comment  'description of the table'
tblproperties  ('creator'='me','created_at'='2012-01-02')//可通过键值对增加配置信息
location '/user/hive/warehouse/mydb.db/employees';

拷贝一张已经存在的表的表模式(而无需拷贝数据):

create table if not exists mydb.employees2
like mydb.employees;

呈现所有表

use mydb;
show tables;
----
employees
employees2

呈现所有表,不在当前数据库情况下:

show tables in mydb;
----
employees
employees2

过滤所需表

show tables '*.ees2'
----
employees2

查看表结构信息:

describe extended mydb.employees;
----
name string employee name
...

查看更详细信息

describe formatted mydb.employees;
----
name string employee name
...

只查看某一列的信息

described mydb.employees.salary;
---
salary float employees salary
管理表vs外部表

上面创建的是所谓的管理表,也被称为内部表;删除表的时候,会删除数据。
现在可以创建外部表,其可以读取所有位于/data/stocks 目录下的以逗号分隔的数据:

create external table if not exists stocks (
    exchange      string,
    symbol        string,
    ymd           string,
    price_open    float,
    price_high    float,
    price_low     float,
    price_close   float,
    volume        int,
    price_adj_close    float
)
row format delimited fields terminated by ','
location  '/data/stocks'

external告诉hive这个表是外部的,location告诉hive数据位于哪个路径。这个表对相关文件无控制权,因此删除表并不会删除数据。
通过describe extended tablename查看表信息的时候,可查看是管理表还是外部表:

...tableType:managed_table;
...tableType:external_table;

用户还可以对一张存在的表进行表结构的复制(不复制数据),这里external关键词决定了无论源表是管理表还是外部表,创建的表都是外部表。

create external table if not exists mydb.employees3
like mydb.employees
location '/path/to/data';

分区表、管理表

分区管理表具有明显的性能优势
先按照country再按照state来对数据进行分析:

create table if not exists mydb.employees(
    name              string                comment    'employee name'
    salary            float                 comment    'employee salary'
    subordinates      array<string>         comment  'names of subordinates'
    deductions        map<string, float>    comment   'names,values'
    address           struct<street:string, city:string, state:string, zip:int> comment 'home address'
)
partitioned by (country string,state string);

之前的表存储在如下目录:

hdfs://master_server/user/hive/warehouse/mydb.db/employees

数据是按照如下子目录存储的:

...
.../employees/country=CA/state=AB
.../employees/country=CA/state=BC
...
.../employees/country=US/state=AL
.../employees/country=US/state=AK
...

如何在分区表查找信息:

select *
from employees
where country = 'US' and state = 'AL'

设置“strice”模式,对分区表查询的时候如果不对分区进行过滤,则任务不会提交:

set hive.mapred.mode = strict;
set hive.mapred.mode = nostrict;

查看所有分区

show partitions employees;
-----
country=CA/state=AB
country=CA/state=BC
...
show partitions employees partition (country='US');
-----
country=US/state=AL
country=US/state=AK
...

如何引用HOME环境变量:

load data local inpath '${env:HOME}/california-employees'
into table employees
patition (country = 'US', state = 'CA');

Hive会把${env:HOME}/california-employees这个目录下面的文件将会拷贝到上述分区目录下。

外部分区表

外部表也可以使用分区,可首先创建分区,然后载入数据

create external table if not exists log_messages(
    hms           int,
    severity      string,
    server        string,
    process_id    int,
    message       string
)
partitoned by (year int, month int, day int)
row format delimited fields terminated by '\t';
//这里不要求location子句

可通过alter table语句可以单独进行增加分区(同样适用于管理表)

alter table log_messages add partition(year=2012,month=1,day=2)
location 'hdfs://master_server/data/log_messages/2012/01/02';

删除表

drop table if exists employees

管理表:删除表的元信息和数据
外部表:删除表的元信息

修改表

修改表只会影响表的元信息,用户需自己确保数据符合元信息要求。

表重命名
alter table log_messages rename to logmsgs;
增加、修改、删除表分区

增加

alter table log_messages add if not exists
partition (year=2012, month=1, day = 1) location '/logs/2011/01/01'
partition (year=2012, month=1, day = 2) location '/logs/2011/01/02'
...

修改

alter table log_messages partition (year=2012, month=1, day = 2) 
set location 's3n:/ourbucket/logs/2011/01/02'

删除

alter table log_messages drop if exists partition (year=2012, month=1, day = 2) 
修改列信息
alter table log_messages
change columns hms hours_minutes_seconds int
comment 'the hours, minutes, and seconds part of the timestamp'
after severity;

重命名、改类型,改列顺序到severity后面(如果想移动到第一个位置则要用first替代after severity
上述语句只修改元数据,用户需保证数据符合元数据的要求。

增加列
alter table log_messages add columns(
    app_name     string   comment 'application name',
    session_id   long     comment 'the current session id'
);
删除或替换列(等于整表替换为如下的列)
alter table log_messages replace columns(
     hours_mins_secs int comment 'hour,minute,seconds from timestamp',
     severity string comment 'The message severity',
     message string comment 'The rest of the message'
)
修改表属性
alter table log_messages set tblproperties (
    'notes' = 'the process id is no longer captured;this column is always NULL'
)

HiveQL:数据操作

向管理表中装载数据

load data local inpath '${env:HOME}/california-employees' 
overwrite into table employees
patition (country='US', state='CA')

local 关键字说明指定的目录是本地的,如果没有local 关键字则应该是分布式文件系统中的路径。
overwrite 关键字说明先删除原先存在的数据,没有这个关键字则不删除。

通过查询语句向表中插入数据
insert overwrite table employees
partition (country = 'US', state = 'OR')
select * from staged_employees se
where se.cnty = 'US' and se.st = 'OR'

如果需要多种对应关系,无需写很多遍上面的语句,按如下格式插入数据效率会高(只需要扫描一遍):

from staged_employees se
insert overwrite table employees
    partition (country = 'US', state = 'OR')
    select * where se.cnty = 'US' and se.st = 'OR'
insert overwrite table employees
    partition (country = 'US', state = 'CA')
    select * where se.cnty = 'US' and se.st = 'CA'
insert overwrite table employees
    partition (country = 'US', state = 'IL')
    select * where se.cnty = 'US' and se.st = 'IL'
动态分区插入
insert overwrite table employees
partition (country, state)
select ...,se.cnty,se.st
from staged_employees se;

hive根据select语句中最后2列来确定分区字段country和state的值

混合使用动态和静态分区
insert overwrite table employees
partition (country = 'US',state)
select  ...,se.cnty,se.st
from staged_employees se
where se.cnty = 'US'

country字段为静态,state是动态值,静态分区键必须在动态分区键之前。
动态分区属性

hive.exec.dynamic.partition 设置为true,表示开启动态分区功能

单个查询语句中创建表并加载数据

create table ca_employees
as select name, salary, address
from employees se
where se.state = 'CA'

创建表并载入数据,不能用于外部表。

导出数据

将所有的字段序列化为字符串写入到文件中

insert overwrite local directory '/tmp/ca_employees'
select name, salary, address
from employees
where state = 'CA';

输入到多个文件

from staged_employees se
insert overwrite directory '/tmp/or_employees'
    select * where se.cty = 'US' and se.st = 'OR'
insert overwrite directory '/tmp/ca_employees'
    select * where se.cty = 'US' and se.st = 'CA'
insert overwrite directory '/tmp/il_employees'
    select * where se.cty = 'US' and se.st = 'IL'

视图

Hive先执行这个视图,然后使用这个结果进行余下后续的查询

create view if not exists shipments(time, part)
comment 'time and parts for shipments。'
tblproperties ('creator' = 'me')
as
select ...;

if not existscomment是可选子句。

  • 复制视图create view shipments2 like shipments;
  • 删除视图drop view if exists shipments
  • 显示视图清单show tables
  • 视图不能作为insert语句和load命令的目标表
  • 视图是只读的

HiveQL 查询

select...from 语句

select e.name,e.salary
from employees e;

查询集合数据

查询数组

注:集合的字符串元素是加上引号的,而基本数据类型string的列值是不加引号的。

select name,subordinates
from employees;
---
John Doe        ["Mary Smith","Todd Jones"]
Mary Smith      ["Bill King"]
Todd Jones      [""]
Bill King       [""]
查询Map
select name,deductions
from employees;
---
John Doe        {"Federal":0.2,"State":0.05,"Insurance":0.1}
Mary Smith      {"Federal":0.2,"State":0.05,"Insurance":0.1}
Todd Jones      {"Federal":0.15,"State":0.03,"Insurance":0.1}
Bill King       {"Federal":0.15,"State":0.03,"Insurance":0.1}        
查询Struct
select name,address
from employees;
---
John Doe        {"street":"1 Michigan Ave.","City":"Chicago","state":"IL","zip":60600}
Mary Smith      {"street":"30 Michigan Ave.","City":"Chicago","state":"IL","zip":60600}
Todd Jones      {"street":"20 Michigan Ave.","City":"Chicago","state":"IL","zip":60600}
Bill King       {"street":"8 Michigan Ave.","City":"Chicago","state":"IL","zip":60600}   

引用集合数据类型中的元素

选取数组元素

注:string数据类型不再加引号

select name,subordinates[0]
from employees;
---
John Doe        Mary Smith
Mary Smith      Bill King
Todd Jones      NULL
Bill King       NULL
引用map元素
select name,deductions["State"]
from employees;
---
John Doe        0.05
Mary Smith      0.05
Todd Jones      0.03
Bill King       0.03  
引用struct的元素,使用“点”符号
select name,address.city
from employees;
---
John Doe        Chicago
Mary Smith      Chicago
Todd Jones      Oak Park
Bill King       Obscuria   

使用正则表达式制定列

select symbol,`price.*`
from stocks;
---
AAPL    195.69    197.88    194.0
AAPL    195.69    197.88    194.0
AAPL    195.69    197.88    194.0

使用列值进行计算

select upper(name),salary,deductions["Federal"]
    ,round(salary * (1-deductions["Federal"]))
from employees;
---
JOHN DOE    10000.0    0.2    8000
MARY SMITH  8000.0     0.2    6400
JOHN DOE    7000.0     0.15   5950

算数运算符

运算符 类型 描述
A+B 数值 A和B相加
A-B 数值 A减去B
A*B 数值 A和B相乘
A/B 数值 A除以B。如果不能整除,那么返回商数。
A%B 数值 A除以B的余数。
A&B 数值 A和B按位取与。
A|B 数值 A和B按位取或。
A^B 数值 A和B按位取异或。
~A 数值 A按位取反。

注:

  1. 两种类型数据计算:值范围较小的数据类型将转换为范围更广的数据类型。
  2. 需要注意数据溢出问题,数据溢出的计算结果不会自动转换为更广泛的数据类型

使用函数

数学函数

返回值类型 样式 描述
bigint round(double d,int n) 返回保留n位小数的近似值
bigint floor(double d) 返回<=d的最大整数
bigint ceil(double d)
ceiling(double d)
返回>=d的最小整数
double rand()
rand(INT seed)
返回一个DOUBLE型的随机数,seed是随机因子
double pow(double d,double p) 计算d的p次幂
double sqrt(double d) 计算d的平方根
double abs(double d) 计算d的绝对值
float sign(double d) 如果d是正数,则返回 1.0;
如果d是负数,则返回-1.0;
否则返回0.0

聚合函数

对多行进行计算,返回一个结果值

返回值类型 样式 描述
bigint count(*) 计算总行数,包括含有NULL值的行
bigint count(expr) 计算expr表达式的值非NULL的行数
bigint count(distinct expr) 计算expr表达式的值排重后非NULL的行数
double sum(col) 计算制定行的值的和
double sum(distinct col) 计算排重后值的和
double avg(col) 计算指定行的值的平均值
double avg(distinct col) 计算排重后值的平均值
double min(col) 计算指定行的最小值
double max(col) 计算指定行的最大值
double percentile(bigint int_expr,p) int_expr在p(范围是[0,1])的百分比数值点
array<double> percentile(bigint int_expr,array(p1[,p2]...)) int_expr在p(范围是[0,1])的百分比数值点
double percentile_approx(bigint int_expr,p[,NB]) int_expr在p(范围是[0,1])的百分比数值点,NB是控制精度(默认是10000)
array<double> percentile(bigint int_expr,array(p1[,p2]...)[, NB]) int_expr在p(范围是[0,1])的百分比数值点,NB是控制精度(默认是10000)
array collect_set(col) 返回集合col元素排重后的数组

注:目前不允许在一个查询语句中使用多于一个的函数(distinct ...)表达式

表生成函数

将单列拓展成多列或者多行

返回值类型 样式 描述
N行结果 explode(array) 返回0到多行结果,每行都对应输入的array数组中的一个元素
N行结果 explode(map) 返回0到多行结果,每行对应每个map键-值对
结果插入表中 inline(array<struct[,struct]>) 将结构体数组提取出来并插入到表中
tuple json_tuple(string jsonstr,p1,p2,...,pn) 接受多个标签名称,对输入的json字符串进行处理,
tuple parse_url_tuple(url,partname1,partname2,...) 从url中解析N个部分信息:HOST,PATH,QUERY,REF,PROTOCOL,AUTHORITY,FILE,USERINFO,QUERY:<KEY_NAME>
N行结果 stack(int n,col1,col2,...,colm) 把M列转换成N行,每行有M/N个字段

注:explode不能和其他字段一起使用,比如select name,explode(map) from ee

Hive函数之explode和inline

其他内置函数

返回值类型 样式 描述
type cast(<expr> as <type>) 将expr转换成type类型的,如果转换失败则返回null
string concat(str1,str2,...) 将字符串拼接成一个字符串,例如concat('ab','cd')的结果是'abcd'
string concat_ws(separator,str1,str2,...) 使用指定分隔符拼接字符串
int find_in_set(s,string) 返回以逗号分隔的字符串中s出现的位置
boolean in test in (val1,val2,...),其表示如果test等于后面任一值,则返回true
int length(str) 计算字符串的长度
int instr(str,substr) str字符串中substr第一次出现的位置
int locate(substr,str[,pos]) 查找字符串str中的pos位置后字符串sbustr第一次出现的位置
string lower(string) 转换为小写字母
string upper(string) 转换为大写字母
string regexp_replace(str,regex,replace) 按照java正则表达式regex将字符串str中符合条件的部分替换成replacement
string repeat(str,int) 重复输出n次字符串s
string reverse(str) 反转字符串
array<array<string>> sentences(str,str lang,str locale) 将输入的字符串转换成句子数组,每个句子由一个单词数组构成
int size(map<k.v>) 返回map中元素的个数
array<string> split(str,str pattern) 按照正则表达式pattern分割字符串,以字符串数组的方式返回
map<str,str> str_to_map(str,delim1,delim2) 将字符串s按照指定分隔符转换成map
string substr(str,start_index,length) 从start位置截取length长度的字符串
string trim(str)
rtrim
ltrim
将字符串空格去掉

时间函数

返回值类型 样式 描述
string from_unixtime(bigin T unixtime[, str format]) 将unix时间戳转换成UTC时间,可通过format规定输出的时间格式
bigint unix_timestamp() 获取当前本地时区下的当前时间戳
bigint unix_timestamp(str date, str pattern) 将指定时间字符串格式字符串转换成unix时间戳:unix_timestamp('2009-01-01','yyyy-MM-dd')
timestamp from_utc_timestamp(timestamp,timezone) 视同输入UTC下的时间戳,返回指定时区的时间戳
timestamp to_utc_timestamp(timestamp,timezone) 视同输入指定时区的时间戳,返回UTC下的时间戳
string to_date(str timestamp) 返回时间字符串的日期部分
int year(str date) 返回年份
int month(str date) 返回月份
int day(str date) 返回天
int hour(str date) 返回小时
int minute(str date) 返回分钟
int second(str date) 返回秒数
int weekofyear(str date) 返回第几周
int datediff(str enddate,str startdate) 相差的天数
str date_add(str startdate,int days) 增加天数
str date_sub(str startdate,int days) 减去天数

LIMIT语句

select  upper(name),salary,deductions["Federal"]
    ,round(salary * (1 - deductions["Federal"]))
from employees
limit 2;

列别名

select  upper(name),salary,deductions["Federal"] as fed_taxes
    ,round(salary * (1 - deductions["Federal"])) as salary_minus_fed_taxes
from employees
limit 2;

嵌套select语句

from (
select  upper(name),salary,deductions["Federal"] as fed_taxes
    ,round(salary * (1 - deductions["Federal"])) as salary_minus_fed_taxes
from employees
) e
select e.name,e.salary_minus_fed_taxes
where e.salary_minus_fed_taxes > 70000;

case...when...then...end 语句

select name,salary
    case
        when salary < 5000 then 'low'
        when salary < 7000 then 'middle'
        else 'high'
    end as bracket
from employees

where语句

select  upper(name),salary,deductions["Federal"] as fed_taxes
    ,round(salary * (1 - deductions["Federal"])) as salary_minus_fed_taxes
from employees
where round(salary * (1 - deductions["Federal"])) > 7000 //不可使用列别名

谓语操作符

运算符 数据类型 描述
A = B 基本类型 如果表达A等于表达B,结果TRUE ,否则FALSE。
A <=> B 基本类型 如果A和B都为null则返回true,其他和(=)操作符结果一致。任一为null则结果为null
A != B
A <> B
所有基本类型 如果A不等于表达式B表达返回TRUE ,否则FALSE。
A < B 所有基本类型 TRUE,如果表达式A小于表达式B,否则FALSE。
A <= B 所有基本类型 TRUE,如果表达式A小于或等于表达式B,否则FALSE。
A > B 所有基本类型 TRUE,如果表达式A大于表达式B,否则FALSE。
A >= B 所有基本类型 TRUE,如果表达式A大于或等于表达式B,否则FALSE。
A [NOT] between B and C 如果表达式A大于或等于表达式B,小于或等于表达式C则返回true
A IS [NOT] NULL 所有类型 TRUE,如果表达式的计算结果为NULL,否则FALSE。
A [NOT] LIKE B 字符串 TRUE,如果字符串模式A匹配到B(简单正则表达式),否则FALSE。%匹配任意数量字符,_匹配单个字符
A RLIKE B
A REGEXP B
字符串 NULL,如果A或B为NULL;TRUE,如果A任何子字符串匹配Java正则表达式B;否则FALSE。

注:一般来说A和B中任一为null,则返回null

关于浮点数比较

select *
from employees
where deductions['Federal'] > 0.2;
---
john 0.2
boss 0.3

为什么会返回0.2呢,这是因为用户写的浮点数0.2,hive会默认保存为double类型“0.200000000001”,而deductions是float类型的,将隐式转换为double类型“0.200000100000”
如何避免呢:可以显示的指出0.2是float类型

select *
from employees
where deductions['Federal'] > cast(0.2 as float);
---
boss 0.3

Group by 语句

group by语句通常和聚合函数一起使用,对分组进行过滤

select year(ymd),avg(price_close)
from stocks
group by year(ymd)
having avg(price_close) > 50;

join 语句

select a.ymd, a.price_close, b.price_close
from stocks a
    join stocks b on a.ymd = b.ymd
where a.symbol = 'AAPL' and b.symbol = 'AAPL'

注:sql不支持“非等值连接”,也不支持在on子句中使用or。

join优化

当连接3个或更多表时,Hive会嘉定最后一个表时最大的表,然后尝试将其它表缓存起来,然后扫面最后那个表进行计算。
可以显示的告诉Hive哪张表是达标:

select /*+STREAMTABLE(s)+*/a.ymd, a.price_close, b.price_close
from stocks a
    join stocks b on a.ymd = b.ymd
where a.symbol = 'AAPL' and b.symbol = 'AAPL'
其他join
  • left outer join
  • outer join
  • right outer join
  • full outer join

注:where语句在连接操作执行后才会执行

left semi-join

比inner join更高效的查询方式,但是只能引用左边表的字段

select s.ymd, s.symbol, s.price_close
from stocks s 
    left semi join dividends d on s.ymd = d.ymd and s.symbol = d.symbol; 
排序 order by 和 sort by

order by 全局排序

select s.ymd, s.symbol, s.price_close
from stocks s
order by s.ymd asc ,s.symbol desc

sort by 只在reducer内部排序,如果有多个reducer,则不保证输出的是整体有序的。

select s.ymd, s.symbol, s.price_close
from stocks s
sort by s.ymd asc ,s.symbol desc

使用distribute by来保证相同的数据会分发到同一个reducer中进行处理:

select s.ymd, s.symbol, s.price_close
from stocks s
distribute by s.symbol    --同一个symbol放到同一个reducer中处理
sort by s.symbol, s.ymd desc

如果上面的语句没有要求按ymd 倒序排列,则可以用cluster by简化:

select s.ymd, s.symbol, s.price_close
from stocks s
cluster by s.symbol 

类型转换

cast(value as TYPE)

抽样查询

分桶抽样
分子是要分为几桶,分子是取回的第几个桶,rand()表示随机排序(如果省略rand(),则返回的结果会始终一致)

select *
from numbers tablessample(bucket 1 out of 2 on rand()) s;
---
2
4
6
8
10
数据块抽样
select *
from numbersflat tablesample(0.1 percent) s;

union all 语句

将两个或多个表进行合并,但是要求对应的字段类型必须一致。

分析函数

分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行。
基本结构:

分析函数() + over(partition by ** order by ** rows between ** and **)

基础数据.png
SELECT cookieid,createtime,pv,
SUM(pv) OVER(PARTITION BY cookieid ORDER BY createtime) AS pv1, -- 默认为从起点到当前行
SUM(pv) OVER(PARTITION BY cookieid ORDER BY createtime ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS pv2, --从起点到当前行,结果同pv1 
SUM(pv) OVER(PARTITION BY cookieid ORDER BY createtime ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS pv3,   --当前行+往前3行
SUM(pv) OVER(PARTITION BY cookieid ORDER BY createtime ROWS BETWEEN 3 PRECEDING AND 1 FOLLOWING) AS pv4,    --当前行+往前3行+往后1行
SUM(pv) OVER(PARTITION BY cookieid ORDER BY createtime ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS pv5   ---当前行+往后所有行  
FROM test1;
-----
cookieid    createtime  pv  pv1  pv2    pv3  pv4  pv5
a           2017-12-01  3    3    3      3    3    3
b           2017-12-00  3    3    3      3    3    3
cookie1     2017-12-10  1    1    1      1    6    26
cookie1     2017-12-11  5    6    6      6    13   25
cookie1     2017-12-12  7    13  13      13   16   20
cookie1     2017-12-13  3    16  16      16   18   13
cookie1     2017-12-14  2    18  18      17   21   10
cookie1     2017-12-15  4    22  22      16   20   8
cookie1     2017-12-16  4    26  26      13   13   4
cookie2     2017-12-12  7    7    7      7    13   14
cookie2     2017-12-16  6    13  13      13   14   7
cookie2     2017-12-24  1    14  14      14   14   1
cookie3     2017-12-22  5    5    5      5     5   5

行数控制(window子句):

  • preceding:往前
  • FOLLOWING:往后
    CURRENT ROW:当前行
    UNBOUNDED:无边界,UNBOUNDED PRECEDING 表示从最前面的起点开始, UNBOUNDED FOLLOWING:表示到最后面的终点

开窗函数

sum

sum()计算的是分区内排序后一个个叠加的值,和order by有关;如果没有order by,不仅分区内没有排序,sum()计算的pv也是整个分区的pv

select cookieid,createtime,pv,
    sum(pv) over(PARTITION BY cookieid ORDER BY createtime) as pv1 
FROM test1
max

返回最大值

min

返回最小值

ntile

NTILE(n),用于将分组数据按照顺序切分成n片,返回当前切片值
注1:如果切片不均匀,默认增加第一个切片的分布
注2:NTILE不支持ROWS BETWEEN

SELECT cookieid,createtime,pv,
NTILE(2) OVER(ORDER BY createtime) AS ntile1, --分组内将数据分成2片
NTILE(3) OVER(ORDER BY createtime) AS ntile2,  --分组内将数据分成3片
NTILE(4) OVER(ORDER BY createtime) AS ntile3   --将所有数据分成4片
FROM test1 
row_number

row_number() 从1开始,按照顺序,生成分组内记录的序列
类似:

  • rank() 生成数据项在分组中的排名,排名相等会在名次中留下空位
  • dense_rank() 生成数据项在分组中的排名,排名相等会在名次中不会留下空位
SELECT cookieid,createtime,pv,
    rank() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rank1,
    dense_rank() OVER(PARTITION BY cookieid ORDER BY pv desc) AS d_rank2,
    row_number() OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn3 
FROM test1 
cume_dist

返回:
{小于等于当前值的行数 \over 分组内总行数}
比如,我们可以统计小于等于当前薪水的人数,所占总人数的比例

SELECT cookieid,createtime,pv,
    round(cume_dist() OVER(ORDER BY pv),2) AS cd1,
    round(cume_dist() OVER(PARTITION BY cookieid ORDER BY pv),2) AS cd2  
FROM test1;

类似的:percent_rank,返回:
{小于等于当前值的行数-1 \over 分组内总行数-1}

LAG 和 LEAD

LAG(col,n,DEFAULT) 用于统计窗口内往上第n行值,第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)

LEAD 函数则与 LAG 相反: LEAD(col,n,DEFAULT) 用于统计窗口内往下第n行值

SELECT cookieid,createtime,pv,
    ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
    LAG(createtime,1,'1970-01-01') OVER(PARTITION BY cookieid ORDER BY createtime) AS lag1,
    LAG(createtime,2) OVER(PARTITION BY cookieid ORDER BY createtime) AS lag2 
FROM test1;
FIRST_VALUE 和 LAST_VALUE

FIRST_VALUE 取分组内排序后,截止到当前行,第一个值;
LAST_VALUE 函数则相反,取分组内排序后,截止到当前行,最后一个值。

SELECT cookieid,createtime,pv,
    ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
    FIRST_VALUE(pv) OVER(PARTITION BY cookieid ORDER BY createtime) AS first  
FROM test1;

窗口函数参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容