美文网首页
数据分析_HiveSQL查询语句

数据分析_HiveSQL查询语句

作者: haidaozheng | 来源:发表于2019-05-12 16:39 被阅读0次

    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;
    

    窗口函数参考文章

    相关文章

      网友评论

          本文标题:数据分析_HiveSQL查询语句

          本文链接:https://www.haomeiwen.com/subject/pyyznqtx.html