Hive表操作----HQL


一、HQL DDL语句–完整建表格式

-- ---------- 案例1: HiveSQL语句 DDL语句之 操作数据表 完整建表格式 ---------------
HQL DDL语句-(完整的)建表语法:
    create [external] table 表名(
        列名1 数据类型 comment '字段的描述信息',
        列名2 数据类型 comment '字段的描述信息',
        列名3 数据类型 comment '字段的描述信息',
        ......
    ) comment '表的描述信息'
    分区          partitioned by(分区字段1 数据类型 comment '字段的描述信息', 分区字段2...)
    分桶          clustered by(分桶字段1, 分桶字段2...) sorted by (排序字段1 asc | desc, 排序字段2...) into 桶的个数 buckets
    行格式切割符   row format delimited | SerDe '指定其它的SerDe类, 即: 不同的切割方式'
    存储方式      stored as TextFile | Orc      行存储或者列存储
    存储位置      location hdfs的文件路径
    表属性信息    tblproperties('属性名'='属性值') 例如: 内外部表, 创建者信息, 压缩协议...
    ;

HQL 常用的数据类型:
    原生类型:
        int         整数
        double      小数
        string      字符串
        timestamp   时间戳, 单位: 毫秒
        date        日期
    复杂类型;
        array   列表(序列)
        map     映射
        struct  结构体
        union   联合体

二、内部表和外部表区别

1. 内部表和外部表的区别:

  1. 建表格式不同.
    内部表: 直接创建即可, 默认就是内部表.
    外部表: 建表是需要加 external关键字.
  2. 权限不同, 是否会删除源文件.
    内部表: 也叫受管理表, 删除内部表时, 不仅会删除元数据(Hive中查不到了), 还会删除源文件(HDFS也查不到了)
    外部表: 只会删除元数据(Hive中查不到了), 不会删除源文件(HDFS中还在)

2. 注意点

细节:
1. 如果某个文件想持久存在(除了Hive用, 其它的框架 例如HBase, Spark也要用), 建Hive表时就选择外部表.
2. 如果某个HDFS文件是随着Hive表的删除而删除的, 就用内部表.

思考:
如果我把外部表删了, 又重新的把外部表创建了出来, 请问: 里边还有之前的数据吗?
答案:
如果表结构, 切割方式, 表的存储位置, 表名等信息不发生改变, 则: 创建出该表后, 默认就有之前的数据.

3. 案例–内部表和外部表

-- --------- 案例2: HiveSQL语句 DDL语句之建表: 内部表 和 外部表 ---------------
-- 1. 创建数据库, 切库.
create database day06;
use day06;
show tables;

-- 2. 创建内部表, 射手表.
create table t_archer_inner(
    id            int comment 'ID',
    name          string comment '英雄',
    hp_max        int comment '最大生命',
    mp_max        int comment '最大法力',
    attack_max    int comment '最高物攻',
    defense_max   int comment '最大物防',
    attack_range  string comment '攻击范围',
    role_main     string comment '主要定位',
    role_assist   string comment '次要定位'
) comment '射手表'
row format delimited fields terminated by '\t';

-- 3. 上传源文件到上述Hive表的HDFS路径下, 然后就可以查看表数据了.
select * from t_archer_inner;

-- 4. 查看表的字段(发现中文注释乱码)
desc t_archer_inner;        -- 查看表结构(简单信息, 列名, 数据类型, 描述信息)
desc formatted t_archer_inner;  -- 查看表的详细信息, 其中: Table type表示表的类型: MANAGEN_TABLE(受管理表, 内部表)  EXTERNAL_TABLE(外部表)

-- 5. 删除内部表
drop table t_archer_inner;      -- 不仅会删除元数据, 还会删除源文件.

-- 6. 创建外部表
create external table t_archer_outer(
    id            int comment 'ID',
    name          string comment '英雄',
    hp_max        int comment '最大生命',
    mp_max        int comment '最大法力',
    attack_max    int comment '最高物攻',
    defense_max   int comment '最大物防',
    attack_range  string comment '攻击范围',
    role_main     string comment '主要定位',
    role_assist   string comment '次要定位'
) comment '射手表'
row format delimited fields terminated by '\t';

-- 7. 上传源文件到上述Hive表的HDFS路径下, 然后就可以查看表数据了.
select * from t_archer_outer;

-- 8. 查看外部表的详细信息
desc formatted t_archer_outer;

-- 9. 删除外部表
drop table t_archer_outer;      -- 只会删除元数据, 不会删除源文件.

-- 10. 思考: 如果我把外部表删了, 又重新的把外部表创建了出来, 请问: 里边还有之前的数据吗?
-- 答案: 如果表结构, 切割方式, 表的存储位置, 表名等信息不发生改变, 则: 创建出该表后, 默认就有之前的数据.
select * from t_archer_outer;

三、扩展_解决hive中文注释乱码问题

具体步骤如下:
    1. 去MySQL的hive3数据库中, 修改Hive的码表信息.    因为Hive的元数据(表名, 列名, 数据类型, 描述信息等)都是在MySQL中存储的.
       即: 执行如下的代码
        -- (1)修改表字段注解和表注解
        use hive3;
        alter table COLUMNS_V2 modify column COMMENT varchar(256) character set utf8;
        alter table TABLE_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;

        -- (2)修改分区字段注解
        alter table PARTITION_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8 ;
        alter table PARTITION_KEYS modify column PKEY_COMMENT varchar(4000) character set utf8;

        -- (3)修改索引注解
        alter table INDEX_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;

    2. 去Linux中(即: node1机器), 修改hive软件的配置信息, 配置文件是: /export/server/hive/conf/hive-site.xml 文件.
       把如下的内容, 添加到 <configuration>  </configuration>标签中即可.
        <!-- 存储元数据mysql相关配置 -->
        <property>
            <name>javax.jdo.option.ConnectionURL</name>
            <value>jdbc:mysql://node1:3306/hive3?createDatabaseIfNotExist=true&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8</value>
        </property>

    3. 在node1机器中, 关闭metastore服务, hiveserver2服务, 然后重启这两个服务.
        kill -9 pid值  pid值
        nohup hive --service metastore &
        nohup hive --service hiveserver2 &

    4. 删除刚才创建的hive表, 然后重新创建即可, 此时: 注释乱码问题已经解决了.

四、HQL DDL操作数据库

1. 准备工作

在正式使用Hive之前, 务必确保你的环境是OK, 即: 以后你每天开启虚拟机之后, 需要做的事情是:

  1. 在node1中启动 hadoop环境, 历史任务服务, metastore服务, hiveserver2服务.
    start-all.sh
    mapred --daemon start historyserver
    nohup hive --service metastore &
    nohup hive --service hiveserver2 &
  2. 查看hiveserver2服务是否成功启动, 如果OK, 则用DataGrip直连Hive即可, 这样就能写HiveSQL语句了.
    lsof -i:10000

2. 案例–操作数据库

-- ----------------------------------- 案例3: HiveSQL语句 DDL语句之 操作数据库 -----------------------------------
-- 1. 查看所有的数据库.
show databases ;

-- 2. 切换数据库.
use day05;

-- 3. 创建数据库, 默认是存储到: HDFS的 /user/hive/warehouse/数据库名.db 这里.
create database day06;      -- 如果重复执行会报错.
create database if not exists day06;      -- 如果day06数据库不存在, 我们再创建. 存在就什么都不操作.

-- 4. 创建数据库的时候, 指定数据库在HDFS上的存储位置.
create database day07 location '/aa';          -- 引号中写的是 HDFS的路径

-- 5. 查看具体的数据库.
show create database day07;     -- 查看数据库的简单信息.
desc database day07;            -- 查看数据库的详细详细.

-- 6. 切换到day07数据库, 创建1个表, 我们看看.
use day07;
create table stu(id int, name string);

-- 7. 删除数据库.
drop database day06;            -- 因为是空库, 所以会直接删除.
drop database day07 cascade;   -- 如果要删除的数据库不是空库, 则后续加上cascade关键字, 会连同数据库, 表一起删除.

五、HQL DDL语句–快速映射表

-- ---------------- 案例4: HQL DDL语句--快速映射表 --------------------------
-- Hive的本质就是: 把HDFS文件映射成Hive表, 然后就可以写HQL来操作它了, 底层会被解析成MR任务, 交由Yarn调度执行, 所需的数据源及执行结果会保存到HDFS上...
-- 1. 创建表.
create table products(
    id int comment '商品id',
    name string comment '商品名',
    price int comment '商品价格',
    cid string comment '分类id'
) comment '商品表'
row format delimited fields terminated by ',';
-- 2. 上传源文件到Hive表的HDFS路径下.
-- 3. 查看表结果.
select * from products;

六、HQL DDL–备份表和删除表数据

1. 备份表

  /*
  问题1: 如何备份表?
  答案:
      方式1: 只复制表结构, 包括: 行切割方式.
          create table 备份表名 like 原表名;        -- 底层不会转成MR任务, 而是直接执行.
      方式2: 复制表结构及表数据, 不包括: 行切割方式.
          create table 备份表名 as select语句;      -- 底层会转MR任务, 来执行.
  */
  -- 1. 切库, 查表.
  use day06;
  show tables;
  
  -- 2. 备份表, 方式1: 只复制表结构.
  drop table t1;
  create table t1 like t_archer_inner;        -- 底层不会转成MR任务, 而是直接执行.
  -- 2.1 查看表结构
  desc t1;                  -- 查看表结构信息, 简单信息
  desc formatted t1;        -- 查看表结构信息, 详细信息
  show create table t1;     -- 查看表结构信息, 建表信息
  
  -- 2.2 查看备份表数据
  select * from t1;       -- 没有数据
  
  -- 2.3 思考: 把 t_archer.txt源文件上传到该表的HDFS路径下, 表中有数据吗, 能成功映射吗?
  select * from t1;   -- 备份的时候, 行切割方式也同步备份了.
  
  
  -- 3. 备份表, 方式2: 复制表结构及表数据
  drop table t2;
  create table t2 as select * from t_archer_inner limit 3;        -- 会转MR
  
  -- 3.1 查看表结构
  desc t2;                  -- 查看表结构信息, 简单信息
  desc formatted t2;        -- 查看表结构信息, 详细信息
  show create table t2;     -- 查看表结构信息, 建表信息
  
  -- 3.2 查看表数据.
  select * from t2;
  
  -- 3.3 思考: 把 t_archer.txt源文件上传到该表的HDFS路径下, 能成功解析吗?
  select * from t2;   -- 备份表只备份结构(列名, 数据类型, 数据), 不会备份表的 切割方式.

2. 删除表数据

  /*
  问题2: 如何删除hive的表数据?
  答案:
      1. hive不支持 delete from 这种方式删除数据, 只支持truncate table清空所有表数据.
      2. hive的外部表是无法删除HDFS源文件的, 所以truncate table语法只针对于内部表有效, 针对于外部表无效.
  */
  
  -- 4. truncate table 删除表数据, 只针对内部表有效, 针对于外部表无效.
  desc formatted t1; -- MANAGED_TABLE, 内部表.
  -- 4.1 删除内部表数据.
  select * from t1;
  delete from t1;         -- 报错, hive不支持delete from
  truncate table t1;      -- 清空表数据, 相当于把HDFS中, 该表对应的源文件给删除了.
  
  -- 4.2 尝试删除外部表数据, 发现: 报错.
  select * from t_archer_outer;
  desc formatted t_archer_outer;  -- EXTERNAL_TABLE, 外部表.
  truncate table t_archer_outer;  -- 报错, truncate table只针对于内部表有效, 针对于外部表无效.

七、HQL DDL–查看及修改表信息

-- ----------- 案例5: HQL DDL--查看及修改表信息 -----------------
-- 1. 查看所有的数据表
show tables;
-- 2. 查看表信息.
desc t_archer_inner;                -- 查看简单信息, 列名, 数据类型, 描述信息
desc formatted  t_archer_inner;     -- 查看详细信息.
show create table t_archer_inner;   -- 查看建表信息

-- 3. 修改表名, 格式: alter table 旧表名 rename to 新表名
alter table t_archer_inner rename to t_archer_i;
-- alter table t_archer_i rename t_archer_inner;   -- 不能省略to, 报错.
-- 4. 修改表的存储路径, 看看就行了, 不建议做, 建议: 统一存储, 统一管理.
select * from t_archer_i;       -- 如果是修改hive表在HDFS的存储路径了, 则hive表数据可能会丢失.
show create table t_archer_i;
-- 格式: alter table 表名 set location 'hdfs文件的路径'
alter table t_archer_i set location '/aa';
-- 5. 修改表属性信息, 内外部表切换.
desc formatted t_archer_i;
alter table t_archer_i set tblproperties('EXTERNAL'='true');    -- 设置为: 外部表, EXTERNAL必须大写, 后边的true或者false大小写均可(建议大写)
alter table t_archer_i set tblproperties('EXTERNAL'='FALSE');   -- 设置为: 内部表, EXTERNAL必须大写, 后边的true或者false大小写均可(建议大写)

-- 6. 修改列的相关操作.
-- 6.0 查看表结构(列名, 数据类型)
desc t_archer_i;
select * from t_archer_i;
-- 6.1 给表新增列.
alter table t_archer_i add columns (kongfu string comment '功夫');
-- 6.2 单独修改指定的列.  注意: string不能直接转成int类型, 反之可以.
-- 格式: alter table 表名 change 旧列名 新列名 新数据类型;
alter table t_archer_i change attack_max a_m string;
alter table t_archer_i change kongfu kf string;     -- 修改kongfu列名为 kf
alter table t_archer_i change kongfu kf int;        -- 报错, string不能直接转int
-- 6.3 修改表中给所有的列.
-- 格式: alter table 表名 replace columns(列1 数据类型, 列2 数据类型)
alter table t_archer_i replace columns (new_id int, new_name string);   -- 用新的2列, 替换之前所有的列(10列)

八、HQL DML语句–数据导入-load data方式

1. DML语句详解

HQL DML语句详解:
    1. 你要分清楚 数据导入 和 数据导出分别指的是什么.
        数据导入:
            Linux, Windows => Hive表中
        数据导出:
            Hive表 => windows, Linux
    2. 数据导入相关语法如下:
        方式1: load data 方式
        方式2: insert into方式
    3. 数据导出相关语法如下:
        insert overwrite

2. load data语法详解

数据导入之 load data语法详解:
    格式:
        load data [local] inpath '源文件路径' [overwrite] into table 表名 [partition by(分区字段1, 分区字段2...)];
    格式详解:
        load data       固定格式, 表示: 数据导入
        local           如果不写, 表示从HDFS路径导入到Hive表, 如果写了, 代表从Linux路径导入到Hive表.
                        Linux系统是本地文件系统, 文件路径前缀为:  file:///     而HDFS文件路径的前缀为: hdfs://node1:8020/
        inpath          后边跟的是具体的()文件路径
        overwrite       如果写了, 就是覆盖写入, 不过不写, 就是追加写入.
        into table      表示具体导入数据到哪个表中.
        partition by    表示具体的分区, 即: 把数据导入到哪个文件夹中.   回顾: 分区 = 分文件夹

    核心细节:
        如果是从Linux文件系统, 导入数据到Hive表, 是从Linux系统中 拷贝一份 上传到HDFS中的.
        如果是从HDFS文件系统, 导入数据到Hive表, 是从HDFS系统中 剪切该文件 到该Hive表的HDFS路径下.
    简单记忆:
        load data导入的时候, Linux是拷贝, HDFS是剪切.

3. 案例–load方式加载数据

-- --------------- 案例1: HQL DML语句 之 load方式加载数据 ----------------------
-- 0. 切库
use day06;
-- 1. 创建王者英雄表, 存储所有英雄的信息.
create table t_all_hero(
    id            int comment 'ID',
    name          string comment '英雄',
    hp_max        int comment '最大生命',
    mp_max        int comment '最大法力',
    attack_max    int comment '最高物攻',
    defense_max   int comment '最大物防',
    attack_range  string comment '攻击范围',
    role_main     string comment '主要定位',
    role_assist   string comment '次要定位'
) comment '王者荣耀英雄表'
row format delimited fields terminated by '\t';

-- 2. load方式加载数据到上述的表中.
-- 方式1: 从Linux路径 -> 导入到Hive表中.
-- 加载 射手数据, Linux路径, 文件前缀是: file:/// 还可以省略不写.
load data local inpath 'file:///export/hivedata/archer.txt' into table t_all_hero;      -- 底层不转MR, 相当于直接把源文件上传到HDFS中.
-- 加载 刺客数据
load data local inpath '/export/hivedata/assassin.txt' into table t_all_hero;
-- 加载 战士数据, 写了overwrite, 表示: 覆盖写入.
load data local inpath '/export/hivedata/warrior.txt' overwrite into table t_all_hero;

-- 方式2: 从HDFS路径 -> 导入到Hive表中.
-- 加载 法师数据到表中.   overwrite: 不写就是追加, 写了就是覆盖.   local不写就是HDFS路径, 写了就是Linux路径.
-- 细节: hdfs://node1:8020 前缀可以省略不写
load data inpath 'hdfs://node1:8020/hivedata/mage.txt' into table t_all_hero;
-- 细节: hdfs://node1:8020 前缀可以省略不写,
load data inpath '/hivedata/tank.txt' overwrite into table t_all_hero;

-- 3. 查看表数据.
select * from t_all_hero;

九、HQL DML语句–数据导入-insert方式

1. insert方式语法格式

格式:
insert into | overwrite table 表名 [partition by(分区字段1, 分区字段2…)] select 语句;

格式解释:
1. into是追加, overwrite是覆盖.
2. into的时候, table关键字可以省略不写, overwrite的时候, table关键字必须写.
3. 上述的语句, 底层会转成MR来执行.

2. insert into方式案例

-- ----------------- 案例2: HQL DML语句 之 insert into方式加载数据 -------------
-- 1. 创建t_all_hero_tmp, 临时的王者荣耀英雄表.
create table t_all_hero_tmp(
    id            int comment 'ID',
    name          string comment '英雄',
    hp_max        int comment '最大生命',
    mp_max        int comment '最大法力',
    attack_max    int comment '最高物攻',
    defense_max   int comment '最大物防',
    attack_range  string comment '攻击范围',
    role_main     string comment '主要定位',
    role_assist   string comment '次要定位'
) comment '王者荣耀英雄表'
row format delimited fields terminated by '\t';

-- 2. 往上述的表中添加数据.
insert into table t_all_hero_tmp select * from t_all_hero limit 5;
insert into t_all_hero_tmp select * from t_all_hero limit 5; -- 细节: into的时候, table可以省略不写.

-- overwrite: 表示 覆盖写入
insert overwrite table t_all_hero_tmp select * from t_all_hero limit 3;     -- table不能省略

-- 3. 查看结果.
select * from t_all_hero_tmp;

十、HQL DML语句–导出数据

1. insert overwrite方式格式

格式:
insert overwrite [local] directory ‘存储该文件的路径’ [row format delimited fields terminated by ‘行格式分隔符’] select 语句;

细节:
1. 不写local就是HDFS路径, 写了就是Linux路径.
2. 行格式分隔符, 表示导出文件后, 内容之间的 分隔符.
3. 导出的时候, 是覆盖导出的, 建议要导出到的目录, 内容为空, 否则啥都没了.

2. 案例–insert overwrite方式

-- ------------- 案例3: HQL DML语句 之 insert overwrite方式 导出数据 -----------------
-- 1. 查看数据.
select * from t_all_hero;       -- 10条数据

-- 2. 导出 t_all_hero表的数据到 hdfs的 /hivedata 目录下, 该目录下是有3个文件的.
insert overwrite directory '/hivedata' select * from t_all_hero;        -- 默认分隔符.

-- 3. 路径同上, 指定 分隔符
insert overwrite directory '/hivedata' row format delimited fields terminated by ':'
select * from t_all_hero;

-- 4. 导出 t_all_hero表的数据到 linux的 /hivedata 目录下, 该目录下是有3个文件的.
insert overwrite local directory '/export/hivedata' row format delimited fields terminated by '$'
select * from t_all_hero;

十一、HQL DQL语句–建表-默认切割符

1. 建表-默认切割符

在创建Hive表的时候, 我们可以直接指定 行格式切割符, 即: 按照什么规则来切割HDFS源文件的每行数据.

如果我们没有指定行格式切割符, 则hive表会用默认的行格式切割符, 即: ‘\001’, 它是1个特殊的字符.
1.在Linu文件x系统中, 显示为: ^A 快捷键: ctrl + v, ctrl + a
2.在windows文件系统中, 显示为: SOH
3.在HDFS文件系统中, 显示为: 口

2. 案例

-- ------------------- 案例1: HQL DQL语句--建表-默认切割符 -----------------------
-- 场景1: 建表, 手动插入数据.
-- 1. 建表.
create table test(
    id int comment '编号',
    name string comment '姓名'
) ;     -- 如果没有指定行格式分隔符, 其实相当于是: row format delimited fields terminated by '\001'

-- 2. 手动往表中添加数据.
insert into test values(1, '乔峰');

-- 3.查看表数据.
-- show create table test;
select * from test;

-- 场景2: 建表, 用于映射指定的文本数据.
drop table team_ace_player;
-- 1. 建表.
create table team_ace_player(
    id int comment '战队编号',
    team_name string comment '战队名',
    ace_name string comment '明星玩家名'
);   -- 默认的切割符是'\001', 不写, 其实相当于写了 row format delimited fields terminated by '\001';

-- 2. 上传源文件.
-- 3. 查看表结果.
select * from team_ace_player;

十二、MySQL和Hive单表查询语法对比

-- ---------------------- 案例2: MySQL 和 Hive 单表查询语法对比 ----------------------
/*
MySQL中, 完整的单表查询, 语法结构如下:
    select
        [distinct] 列1, 列2...
    from 表名
    where 组前筛选
    group by 分组字段
    having 组后筛选
    order by 排序字段 asc | desc
    limit 起始索引, 数据条数;

Hive中, 完整的单表查询, 语法结构如下:
    [CTE表达式]
    select
        [distinct | all] 列1, 列2...
    from 表名
    where 组前筛选
    group by 分组字段
    having 组后筛选
    order by 排序字段 asc | desc
    cluster by 分桶排序字段 | distribute by 分桶字段 sort by 排序字段 asc | desc
    limit 起始索引, 数据条数;

对比上述的 MySQL 和 Hive的单表语法, 会发现, 有如下3点不同:
    1. Hive支持CTE表达式的写法, 可以临时的存储某些语句的执行结果, 方便查询.
    2. hive中除了distinct关键字之外, 还支持all关键字写法.
    3. hive支持分桶查询, 即: cluster by 分桶排序字段
    4. 如果只分桶就写 distribute by 分桶字段, 如果还要排序就写 sort by 排序字段 asc | desc
       如果分桶和排序字段是同一个字段, 则可以直接写 cluster by, 即: cluster by = distribute by + sort by
*/

十三、HQL DQL–基本查询

-- ---------------------- 案例3: HQL DQL语句--基本查询 ----------------------
-- 1. 建库, 切库, 查表.
create database day08;
use day08;
show tables;

-- 2. 建表.
CREATE TABLE orders (
    orderId bigint COMMENT '订单id',
    orderNo string COMMENT '订单编号',
    shopId bigint COMMENT '门店id',
    userId bigint COMMENT '用户id',
    orderStatus tinyint COMMENT '订单状态 -3:用户拒收 -2:未付款的订单 -1:用户取消 0:待发货 1:配送中 2:用户确认收货',
    goodsMoney double COMMENT '商品金额',
    deliverMoney double COMMENT '运费',
    totalMoney double COMMENT '订单金额(包括运费)',
    realTotalMoney double COMMENT '实际订单金额(折扣后金额)',
    payType tinyint COMMENT '支付方式,0:未知;1:支付宝,2:微信;3、现金;4、其他',
    isPay tinyint COMMENT '是否支付 0:未支付 1:已支付',
    userName string COMMENT '收件人姓名',
    userAddress string COMMENT '收件人地址',
    userPhone string COMMENT '收件人电话',
    createTime timestamp COMMENT '下单时间',
    payTime timestamp COMMENT '支付时间',
    totalPayFee int COMMENT '总支付金额'
) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

-- 3. 上传源文件, 或者 load data方式加载数据.
-- 4. 查看表数据.
select * from orders;   -- 1000条

-- 5. 完成如下的需求.
-- 5.1 查询所有
select * from orders;   -- 1000条
select * from orders limit 100;   -- 10条, 实际开发中写法
-- 5.2 查询单列
select userName, orderId, totalMoney from orders;
-- 5.3 查询数据量
select count(orderId) from orders;        -- 1000条
-- 5.4 过滤广东省订单
select * from orders where userAddress like '广东省%';
-- 5.5 找出广东省单笔营业额最大的订单
-- 思路1: 排序.
select * from orders where userAddress like '广东省%' order by realTotalMoney desc limit 1;
-- 思路2: 子查询.
select *
from
    orders
where
      userAddress like '广东省%'
  and realTotalMoney = (select max(realTotalMoney) from orders where userAddress like '广东省%');

-- 5.6 统计未支付、已支付各自的人数
-- 方式1: 分组统计.
select
    case
        when isPay = 0 then '未支付'
        when isPay = 1 then '已支付'
    end as isPay,
    case isPay
        when 0 then '未支付'
        when 1 then '已支付'
    end as isPay2,
    count(orderId)
from
    orders
group by
    isPay;

-- 思路1: if()函数直接实现.     if(判断条件, 值1, 值2);  条件成立返回值1, 不成立返回值2
select
    count(if(isPay = 0, isPay, null)) as `未支付`,
    count(if(isPay = 1, isPay, null)) as `已支付`
from orders;

-- 5.7 在已付款订单中,统计每个用户最高的一笔消费金额
select userId, max(realTotalMoney) from orders where isPay = 1 group by userId;
-- 5.8 统计每个用户的平均订单消费额
select userId, userName, avg(realTotalMoney) from orders  group by userId, userName;
-- 升级需求: 保留两位小数.
select userId, userName, round(avg(realTotalMoney), 2) as avg_money from orders  group by userId, userName;
-- 5.9 统计每个用户的平均订单消费额,过滤大于10000的数据
-- 细节: having后边可以跟聚合函数, 不能直接写其它的 数字函数.
select userId, userName, avg(realTotalMoney) as avg_money from orders  group by userId, userName having avg_money > 10000;
-- 四舍五入, 保留两位小数, 组后筛选, 写法如下.
select
    userId,
    userName,
    round(avg(realTotalMoney), 2) as avg_money
from
    orders
group by
    userId, userName
having
    round(avg(realTotalMoney), 2) > 10000;


-- 细节: 保留两位小数.
select round(10.123, 2);    -- 10.12
select round(10.125, 2);    -- 10.13

十四、HQL DQL语句–join连接查询

-- ---------------------- 案例4: HQL DQL语句--join连接查询 ----------------------
-- join连接查询是多表查询的方式, 它具体有 6种查询方式, 分别是: 交叉连接, 内连接, 左外连接, 右外连接, 满外连接(全外连接), 左半连接, 具体如下:
-- 1. 建表, 上传源文件.
--table1: 员工表
CREATE TABLE employee(
   id int,      -- 员工id
   name string,
   deg string,
   salary int,
   dept string
 ) row format delimited fields terminated by ',';

--table2:员工家庭住址信息表
CREATE TABLE employee_address (
    id int,     -- 员工id
    hno string,
    street string,
    city string
) row format delimited fields terminated by ',';

-- 2. 查看表数据.
select * from employee;
select * from employee_address;

-- 3. 演示各种连接查询.
-- 3.1 交叉连接查询 cross join, 查询结果是: 两张表的笛卡尔积, 即: 表A总条数 * 表B总条数, 会有大量的脏数据, 一般不用.
-- 写法1: 标准写法.
select * from employee cross join employee_address;     -- 25条
-- 写法2: 语法糖
select * from employee, employee_address;     -- 25条

-- 3.2 内连接查询, inner join, 其中inner可以省略不写, 查询结果为: 表的交集.
-- 写法1: 标准写法.  显式内连接
select * from employee e1 inner join employee_address e2 on e1.id = e2.id;  -- 4条
select * from employee e1 join employee_address e2 on e1.id = e2.id;  -- 4条

-- 写法2: 语法糖, 隐式内连接.
select * from employee e1, employee_address e2 where e1.id = e2.id;  -- 4条

-- 3.3 左外连接查询, left outer join, 其中outer可以省略不写, 查询结果为: 左表的全集 + 表的交集.
select * from employee e1 left outer join employee_address e2 on e1.id = e2.id; -- 5条
select * from employee e1 left join employee_address e2 on e1.id = e2.id; -- 5条

-- 3.4 右外连接查询, right outer join, 其中outer可以省略不写, 查询结果为: 右表的全集 + 表的交集.
select * from employee e1 right outer join employee_address e2 on e1.id = e2.id; -- 5条
select * from employee e1 right join employee_address e2 on e1.id = e2.id; -- 5条

-- 3.5 满外连接(全外连接)查询, full outer join, 其中outer可以省略不写, 查询结果为: 左表全集 + 右表全集 + 表的交集.
-- 细节: 满外连接 = 左外连接 + 右外连接 查询结果.
select * from employee e1 full outer join employee_address e2 on e1.id = e2.id; -- 6条
select * from employee e1 full join employee_address e2 on e1.id = e2.id; -- 6条

-- 3.6 左半连接, left semi join, , 查询结果为: 表的交集.
-- 细节: 左半连接 相当于 内连接的查询结果, 只要左表部分.
select * from employee e1 left semi join employee_address e2 on e1.id = e2.id; -- 4条, 只有左表的数据.

十五、HQL DQL语句–分桶查询

1. 分桶查询

分桶查询介绍:
    概述:
        分桶查询就是根据分桶字段, 把表数据分成n份, 但是: 是逻辑划分, 不是物理划分.
        逻辑划分: 类似于分组, 就是根据分桶字段值 进行分组, HDFS上文件还是1.
        物理划分: 就是昨天的分桶建表, HDFS上存储数据的时候, 已经变成了N个文件.
    格式:
        cluster by 分桶排序字段 | distribute by 分桶字段 sort by 排序字段 asc | desc
    细节:
        1. 分桶查询是 逻辑分桶, 把数据分成n组进行查询, 但是HDFS上还是1个文件.
           分桶建表是 物理分桶, 数据在HDFS上会被存储到N个文件几种.
        2. 分桶查询需要用到 set mapreduce.job.reduces = n; 这个n就是ReduceTask任务的数量, 即: 分几个桶.
        3. mapreduce.job.reduces 参数的值默认是 -1, 即: 程序会按照数据量, 任务量自动分配ReduceTask的个数, 一般是1, 即: 1个桶.
        4. distribute by 表示分桶, sort by表示对桶内的数据进行排序(局部排序), 如果分桶字段和排序字段是同1, 则可以简写为: cluster by
           即: cluster by = distribute by + sort by
        5. 面试题: cluster by, distribute by, sort by, order by这四组关键字的区别是什么?
            cluster by:     分桶且(桶内局部)排序的, 分桶字段和排序字段必须是同1个字段, 且是升序排列.
            distribute by:  仅分桶的, 一般要结合 set mapreduce.job.reduces = n;参数一起使用.
            sort by:        桶内排序(即: 局部排序), 一般要结合 distribute by 一起使用.
            order by:       全局排序的, 对全表数据进行排序, 和cluster by冲突, 不能共用.

2. 案例–分桶查询

-- ---------------------- 案例5: HQL DQL语句--分桶查询 ----------------------
-- 1. 建表, 上传源文件, 查看表数据.
create table student(
    sid int,
    name string,
    gender string,
    age int,
    major string
) comment '学生信息表'
row format delimited fields terminated by ',';
select * from student;      -- 22条

-- 2. 按照性别进行分桶, 分成2个桶...
-- 核心细节, 分桶查询是, 需要设置ReduceTask的任务数, 有几个ReduceTask, 就有几个桶.
set mapreduce.job.reduces = 2;  -- 默认是-1, 即: 程序会根据数据量, 任务量, 自动给出 ReduceTask任务数, 一般是: 1
select * from student distribute by gender;        -- 根据gender分桶, 且根据gender升序排列.

-- 3. 按照id分成3个桶, 注意: 不排序.
set mapreduce.job.reduces = 3;
select * from student distribute by sid;

-- 4. 上述的数据, 虽然分成了3个桶, 但是不方便查看数据, 因此, 加入: 排序.
-- 按照id分成3个桶, 然后按照年龄降序排列.
select * from student distribute by sid sort by age;    -- 默认是升序.
select * from student distribute by sid sort by age desc;    -- 降序

-- 5. 如果分桶字段和排序字段是同1个, 则可以简写为: cluster by
-- 根据sid分成3个桶, 且根据sid升序排列.
select * from student distribute by sid sort by sid;    -- 默认是升序.
select * from student cluster by sid;       -- 效果同上.
-- select * from student cluster by sid desc;       -- 报错, cluster by默认升序.

十六、HQL DQL–随机抽样

1. 随机抽样(采样)

随机抽样解释:
    概述:
        随机采样指的是 tablesample()函数, 通过它, 我们可以用 类似于分桶的思路, 对数据进行采样.
    格式:
        select .. from 表名 tablesample(bucket x out of y on 列名 | rand());
    格式解释:
        1. y表示: 把数据分成y个桶.   逻辑分桶.
        2. x表示: 从y个分桶中, 获取第x份数据.
        3. 如果是列名方式, 列名采样, 在列名等其它条件不发生改变的情况下, 每次采样获取的数据都是一样的.
        4. 如果是rand()函数, 随机采样, 则: 每次获取的数据都是不一样的.
        5. x 不能大于 y

2. 案例–随机抽样(采样)

-- ---------------------- 案例6: HQL DQL语句--随机抽样(采样) ----------------------
-- 1. 查看原表数据.
select * from student;      -- 22条, 12条男, 10条女

-- 2. 按照 性别分成2个桶, 取第1份数据.
select * from student tablesample ( bucket 1 out of 2 on gender);   -- 10条, 女
-- 3. 按照 性别分成2个桶, 取第2份数据.
select * from student tablesample ( bucket 2 out of 2 on gender);   -- 12条, 男

-- 4. 演示rand()函数
select rand();      -- 随机数, 生成0.0 ~ 1.0之间的数字, 包左不包右, 也叫: 前闭后开.  [0.0, 1.0)

-- 5. 随机采样, 分成3个桶, 取第1份数据.
select * from student tablesample ( bucket 1 out of 3 on rand());   -- 每次获取的数据条数都不一样.
select * from student tablesample ( bucket 4 out of 3 on rand());   -- 报错, x不能大于y

-- 也可以换成其它的表进行采样.
select * from orders tablesample ( bucket 1 out of 3 on rand());

十七、HQL DQL–正则查询

1. 正则查询

正则查询介绍:
    概述:
        正则表达式不独属于任意的一种语言, 市场上绝大多数的语言都支持它, 例如: Java, Python, JavaScript, HiveSQL...
        正则的规则是通用的, 但是正则表达式的校验格式(语法)稍有不同.
        正则表达式: 正确的, 符合特定规则的字符串. (RegExp, 全称: regular expression)
    常用的正则规则(通用):
        .       代表任意的1个字符
        \.      代表1个普通的. 没有任何的特殊含义.
        [abc]   代表a,b,c中任意的1个字符.
        [^abc]  代表除了a,b,c以外, 任意的1个字符
        \d      代表任意的1个数字, 等价于 [0-9]
        \w      代表1个单词字符, 即: 数字, 字母, 下划线, 等价于: [a-zA-Z0-9_]
        \S      代表任意的1个非空字符
        \\      代表1个\
        ^       代表开头
        $       代表结尾
        ?       数量词, 代表前边的内容出现0次或者1次.
        *       数量词, 代表前边的内容出现0次或多次.
        +       数量词, 代表前边的内容出现1次或者多次.
        a{n}    数量词, 代表a恰好出现n次, 多一次少一次都不行.
        a{n,}   数量词, 代表a至少出现n次, 至多出现无数次.
        a{n,m}  数量词, 代表a至少出现n次, 至多出现m次, 包括n和m
    HiveSQL中, 正则校验格式如下:
        字符串 rlike '正则表达式'

2. 案例–正则查询

-- ---------------------- 案例7: HQL DQL语句--正则查询 ----------------------
-- 1. 校验字符串是否以a开头.
select '1abc' rlike '^a.*';   -- false
select 'a' rlike '^a.*';   -- true

-- 2. 校验字符串以x结尾.
select 'abcx1' rlike '.*x$';    -- false
select 'abcx' rlike '.*x$';     -- true

-- 3. 校验字符串中是否包含连续的3个a
select '11aaaabc' rlike '^.*a{3}.*$';   -- true
select '11aa' rlike '^.*a{3}.*$';       -- false

-- 4. 校验字符串是否不以a,b,c任意的1个字母开头.
select 'a123' rlike '^[^abc].*';     -- false
select 'bcd' rlike '^[^abc].*';     -- false
select 'c123cd' rlike '^[^abc].*';     -- false
select 'd123' rlike '^[^abc].*';     -- true

-- 5. 校验手机号是否合法.
-- 规则: 1. 纯数字组成.  2.长度必须是11位.  3.第1位数字必须是1.  4.第2位数字可以是: 3-9
select '13112345678' rlike '^1[3-9][0-9]{9}$';
select '13112345678' rlike '^1[3-9]\\d{9}$';

-- 6. 完成如下的需求
-- 6.1 查找广东省的数据
select * from orders where userAddress like '广东省%';        -- 模糊查询
select * from orders where userAddress rlike '^广东省.*';     -- 正则查询

-- 6.2 查找用户地址是:xx省 xx市 xx区的数据
select * from orders where userAddress rlike '.*省.*市.*区';     -- 正则查询

-- 6.3 查找用户姓为张、王、邓
select * from orders where userName rlike '^[张王邓]\\S+';     -- \S: 代表任意的1个非空白字符
select * from orders where userName rlike '^[张王邓].+';

-- 6.4 查找手机号符合:188****0*** 规则
select * from orders where userPhone rlike '^188\\*{4}0\\d{3}$';

十八、HQL DQL–union联合查询

1. union 联合查询

union 联合查询介绍:
    概述:
        就是对表数据做纵向拼接的, 类似于书本的 上, 下册, 有两种拼接方式.
    分类:
        union distinct      -- distinct可以省略不写, 合并 并去重.
        union all           -- 合并 不去重.
    细节:
        1. union alldistinct 作用类似, 都是纵向合并, 区别就是: 去不去重的问题.
        2. 直接写union 默认是 union distinct, 即: 去重合并.
        3. 要进行union联合查询的数据, 列的个数, 对应的数据类型都要一致.
        4. 如果条件写到上边的 查询语句后, 则: 单独作用于该SQL.
           如果条件写到下边的 查询语句后, 则: 作用于全局.
        5. full outer joinunion all的区别?
            1. 作用不同.
                full join: 横向合并.
                union all: 纵向合并.
            2. 条件要求不一致.
                full join: 对表的列数, 数据类型无要求.
                union all: 要求联合查询的表的列数, 数据类型都要保持一致.

2. 案例–union 联合查询

-- ---------------------- 案例8: HQL DQL语句--union联合查询 ----------------------
-- 1. 查看数据源表.
use day07;      -- 为了方便演示.
show tables;

select * from day07.student;              -- 22条;
select * from day07.student_buckets;      -- 22条;

-- 2. union all演示, 合并 不去重.
select * from student
union all
select * from student_buckets;      -- 44条;

-- 3. union distinct演示, 合并,去重.
select * from student
union distinct
select * from student_buckets;      -- 22条;

-- 4. union distinct演示, 合并,去重.
select * from student
union   -- distinct 可以省略不写.
select * from student_buckets;      -- 22条;

-- 5. 如果条件写到上边的 查询语句后, 则: 单独作用于该SQL.
(select * from student limit 3)     -- 3条
union all
select * from student_buckets;      -- 25条;

-- 6. 如果条件写到下边的 查询语句后, 则: 作用于全局.
select * from student                       -- 22条
union all
select * from student_buckets limit 3;      -- 3条;

-- 6. 如果仅仅是单独作用于某1个SQL, 则可以用括号括起来.
select * from student                         -- 22条
union all
(select * from student_buckets limit 3);      -- 25条;

十九、HQL DQL语句–虚拟列查询

1. 虚拟列查询

虚拟列查询介绍:
    概述:
        虚拟列是Hive内置的可以在查询语句中使用的特殊标记,可以查询数据本身的详细参数。
    大白话:
        虚拟列是Hive内置的, 可以直接用的参数, 辅助我们进行查询的.
    Hive目前可用3个虚拟列:
        INPUT__FILE__NAME           显示数据行 所在的具体文件                                      类似于: 你在哪个班.
        BLOCK__OFFSET__INSIDE__FILE 显示数据行 所在文件的偏移量, 偏移量从0开始计数.                   类似于: 你是班级的第几个人.
            文件内容如下:             对应的 行偏移量:
            95001,李勇,,20,CS         0
            95002,刘晨,,19,IS         23
            95003,王敏,,22,MA         46
        ROW__OFFSET__INSIDE__BLOCK  显示数据所在HDFS块的偏移量, 即: 该行数据在HDFS文件的那个Block块中. 类似于: 你在班级的哪个组.
            此虚拟列需要设置:SET hive.exec.rowoffset=true 才可使用
    细节:
        1. 中文在utf-8码表中占 3 个字节, 在gbk码表中占2个字节.
        2. 数字, 字母, 特殊符号无论在什么码表, 都只占 1个字节.
        3. HDFS文件和Linux文件类似, 默认的换行符都是: \n

2. 案例–虚拟列查询

-- ------------------ 案例9: HQL DQL语句--虚拟列查询(Virtual Columns) ------------------
-- 1. 查看数据源表.
use day08;
select * from student;

-- 2. 查看 day08#student 数据表映射的是哪个文件.
select *, INPUT__FILE__NAME from student;       -- hdfs://node1.itcast.cn:8020/user/hive/warehouse/day08.db/student/students.txt

-- 3. 查看 day08#student 数据表每行数据 在映射文件中的 起始索引(行偏移量)
select *, BLOCK__OFFSET__INSIDE__FILE from student;     -- 行偏移量从: 0开始.
-- 细节: 上述方式可以帮助我们筛选出中间的某些数据.
select *, BLOCK__OFFSET__INSIDE__FILE from student where BLOCK__OFFSET__INSIDE__FILE > 100; -- 获取行偏移量大于100的数据.

-- 4. 查看 day08#student 数据表每行数据 在HDFS的文件的哪个Block块中.  因为HDFS文件是分块存储的, 每个块的大小是128MB.
-- 核心细节: 设置HDFS的块偏移量, block块从 0 开始计数.
SET hive.exec.rowoffset=true;
select *, ROW__OFFSET__INSIDE__BLOCK from student;      -- 因为映射的students.txt文件较小, 达不到128MB, 所以该文件只有1个Block块.

-- 5. 汇总查看
select *,
       INPUT__FILE__NAME,               -- 该行数据在 那个HDFS文件中.             类似于: 你在哪个班.
       BLOCK__OFFSET__INSIDE__FILE,     -- 该行数据在 HDFS文件中的 行偏移量        类似于: 你是咱们班的第几个学生
       ROW__OFFSET__INSIDE__BLOCK       -- 该行数据在 HDFS文件的 哪个Block块.      类似于: 你在班级的哪个组.
from
    student;

二十、HQL DQL语句–CTE表达式

1. CTE表达式

CTE表达式介绍:
    概述:
        全称叫 common table expression, 公共表表达式, 就是用于 临时存储某些结果数据 的.
    格式:
        with cte表达式的名字 as (
            select 语句, 即: 要被临时存储的内容
        )
        select ... from cte表达式的名字;
    写法:
        1. 标准写法.
        2. from风格.
        3. 链式编程.
        4. 结合union all 或者 join查询.
        5. 用数据表永久存储结果.
        6. 用视图临时存储结果.

2. 案例–CTE表达式

-- ---------------------- 案例10: HQL DQL语句--CTE表达式 ----------------------
/*
CTE表达式介绍:
    概述:
        全称叫 common table expression, 公共表表达式, 就是用于 临时存储某些结果数据 的.
    格式:
        with cte表达式的名字 as (
            select 语句, 即: 要被临时存储的内容
        )
        select ... from cte表达式的名字;
    写法:
        1. 标准写法.
        2. from风格.
        3. 链式编程.
        4. 结合union all 或者 join查询.
        5. 用数据表永久存储结果.
        6. 用视图临时存储结果.
*/
-- 1. cte表达式入门写法.
with t1 as (
    select * from student
)
select * from t1;

-- 2. from风格.
with t1 as (
    select * from student
)
from t1 select sid, name;

-- 3. 链式编程(链式风格)
with t1 as ( select * from student),            -- 22条, 全列
     t2 as ( select * from t1 limit 10),        -- 10条, 全列
     t3 as ( select sid, name, age from t2)     -- 10条, 3列
select * from t3;

-- 4. cte结合union语句一起使用, 联合查询.
-- 3. 链式编程(链式风格)
with t1 as ( select * from student),            -- 22条, 全列
     t2 as ( select * from t1 limit 10)         -- 10条, 全列
select * from t1
union all           -- 如果不写, 默认是 distinct
select * from t2;       -- 32条, 5列

-- 扩展, 演示下 full outer join 全外连接.
with t1 as ( select * from student),            -- 22条, 全列
     t2 as ( select * from t1 limit 10)         -- 10条, 全列
select * from t1
full join t2
on t1.sid = t2.sid;     -- full join: 满外连接, 横向拼接.  22条, 10列,  10行全列, 12行(5列值, 5列空)

-- 5. 我们可以用 数据表 把cte结果 永久存储.
show tables;

create table hg1 as
with t1 as (
    select * from student
)
select sid, name, age from t1 limit 10;

-- 查看备份结果.
select * from hg1;

-- 6. 我们可以用 视图 把cte结果 永久存储.
show tables;

create view hg2 as      -- 视图是存储在内存中的, 临时存储.
with t1 as (
    select * from student
)
select sid, name, age from t1 limit 5;

select * from hg2;  -- 从视图中查询数据.

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值