335 lines
11 KiB
Markdown
335 lines
11 KiB
Markdown
# Hive SQL 语法参考
|
||
|
||
## 数据类型
|
||
|
||
| 类型 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| TINYINT | 1字节整数 | level TINYINT |
|
||
| SMALLINT | 2字节整数 | age SMALLINT |
|
||
| INT | 4字节整数 | count INT |
|
||
| BIGINT | 8字节整数 | id BIGINT |
|
||
| FLOAT | 4字节浮点 | score FLOAT |
|
||
| DOUBLE | 8字节浮点 | price DOUBLE |
|
||
| DECIMAL(p,s) | 定点数 | amount DECIMAL(18,2) |
|
||
| BOOLEAN | 布尔 | active BOOLEAN |
|
||
| STRING | 变长字符串 | name STRING |
|
||
| VARCHAR(n) | 变长字符串(限长) | code VARCHAR(50) |
|
||
| CHAR(n) | 定长字符串 | flag CHAR(1) |
|
||
| DATE | 日期 | birth_date DATE |
|
||
| TIMESTAMP | 时间戳(纳秒精度) | created_at TIMESTAMP |
|
||
| BINARY | 二进制 | data BINARY |
|
||
| ARRAY\<type\> | 数组 | tags ARRAY\<STRING\> |
|
||
| MAP\<k,v\> | 映射 | props MAP\<STRING,STRING\> |
|
||
| STRUCT\<f1:t1,...\> | 结构体 | user STRUCT\<id:INT,name:STRING\> |
|
||
| UNIONTYPE\<t1,t2,...\> | 联合类型 | value UNIONTYPE\<INT,STRING\> |
|
||
|
||
---
|
||
|
||
## 时间函数
|
||
|
||
```sql
|
||
-- 当前时间
|
||
current_date() -- 当前日期
|
||
current_timestamp() -- 当前时间戳
|
||
unix_timestamp() -- 当前 Unix 时间戳(秒)
|
||
|
||
-- 格式转换
|
||
date_format(date_col, 'yyyy-MM-dd') -- 日期格式化
|
||
date_format(timestamp_col, 'yyyy-MM-dd HH:mm:ss') -- 时间格式化
|
||
to_date(string_col) -- 字符串转日期
|
||
to_date(string_col, 'yyyy-MM-dd') -- 字符串转日期(带格式)
|
||
from_unixtime(timestamp) -- Unix 时间戳转字符串
|
||
from_unixtime(timestamp, 'yyyy-MM-dd') -- 带格式转换
|
||
|
||
-- 日期计算
|
||
date_add(date_col, 7) -- 加7天
|
||
date_sub(date_col, 7) -- 减7天
|
||
add_months(date_col, 3) -- 加3个月
|
||
datediff(end_date, start_date) -- 日期差(天数)
|
||
months_between(date1, date2) -- 月份差
|
||
|
||
-- 日期提取
|
||
year(date_col) -- 年
|
||
month(date_col) -- 月
|
||
day(date_col) -- 日
|
||
dayofmonth(date_col) -- 月中第几天
|
||
dayofweek(date_col) -- 周几 (1=周日, 7=周六)
|
||
hour(timestamp_col) -- 时
|
||
minute(timestamp_col) -- 分
|
||
second(timestamp_col) -- 秒
|
||
quarter(date_col) -- 季度 (1-4)
|
||
weekofyear(date_col) -- 年中第几周
|
||
last_day(date_col) -- 月末日期
|
||
trunc(date_col, 'MM') -- 月初日期
|
||
trunc(date_col, 'YY') -- 年初日期
|
||
|
||
-- Unix 时间戳
|
||
unix_timestamp(date_col) -- 转 Unix 时间戳
|
||
unix_timestamp(string_col, 'yyyy-MM-dd') -- 指定格式转换
|
||
from_unixtime(timestamp) -- Unix 时间戳转字符串
|
||
```
|
||
|
||
---
|
||
|
||
## 字符串函数
|
||
|
||
```sql
|
||
-- 常用函数
|
||
concat(str1, str2, ...) -- 字符串拼接
|
||
concat_ws('-', str1, str2, ...) -- 用分隔符拼接
|
||
lower(str) -- 转小写
|
||
upper(str) -- 转大写
|
||
trim(str) -- 去两端空格
|
||
ltrim(str) -- 去左空格
|
||
rtrim(str) -- 去右空格
|
||
length(str) -- 字符串长度
|
||
substring(str, pos, len) -- 截取字符串(pos从1开始)
|
||
substr(str, pos, len) -- 同 substring
|
||
left(str, len) -- 取左边len个字符
|
||
right(str, len) -- 取右边len个字符
|
||
reverse(str) -- 反转字符串
|
||
repeat(str, n) -- 重复n次
|
||
space(n) -- 生成n个空格
|
||
|
||
-- 查找与替换
|
||
instr(str, substr) -- 查找子串位置
|
||
locate(substr, str, pos) -- 从pos位置查找
|
||
replace(str, old, new) -- 替换
|
||
regexp_extract(str, pattern, idx) -- 正则提取
|
||
regexp_replace(str, pattern, replacement) -- 正则替换
|
||
|
||
-- 分割
|
||
split(str, delimiter) -- 分割成数组
|
||
|
||
-- 其他
|
||
initcap(str) -- 首字母大写
|
||
lpad(str, len, pad) -- 左填充
|
||
rpad(str, len, pad) -- 右填充
|
||
hex(col) -- 转16进制
|
||
unhex(str) -- 16进制转字符串
|
||
```
|
||
|
||
---
|
||
|
||
## 聚合函数
|
||
|
||
```sql
|
||
-- 基础聚合
|
||
COUNT(*) -- 计数(含NULL行)
|
||
COUNT(col) -- 计数(不含NULL)
|
||
COUNT(DISTINCT col) -- 去重计数
|
||
SUM(col) -- 求和
|
||
AVG(col) -- 平均值
|
||
MIN(col) -- 最小值
|
||
MAX(col) -- 最大值
|
||
|
||
-- 集合聚合
|
||
collect_list(col) -- 返回数组(不去重)
|
||
collect_set(col) -- 返回数组(去重)
|
||
|
||
-- 统计函数
|
||
variance(col) -- 方差
|
||
var_pop(col) -- 总体方差
|
||
var_samp(col) -- 样本方差
|
||
stddev(col) -- 标准差
|
||
stddev_pop(col) -- 总体标准差
|
||
stddev_samp(col) -- 样本标准差
|
||
|
||
-- 近似函数
|
||
approx_count_distinct(col) -- 近似去重计数(大数据量优化)
|
||
|
||
-- 其他
|
||
first(col) -- 第一个值
|
||
last(col) -- 最后一个值
|
||
```
|
||
|
||
---
|
||
|
||
## 条件表达式
|
||
|
||
```sql
|
||
-- CASE WHEN
|
||
CASE
|
||
WHEN condition1 THEN result1
|
||
WHEN condition2 THEN result2
|
||
ELSE default_result
|
||
END
|
||
|
||
-- CASE 字段匹配
|
||
CASE field
|
||
WHEN value1 THEN result1
|
||
WHEN value2 THEN result2
|
||
ELSE default_result
|
||
END
|
||
|
||
-- COALESCE(取第一个非空值)
|
||
COALESCE(col1, col2, default_value)
|
||
|
||
-- NULLIF(相等返回NULL)
|
||
NULLIF(col1, col2)
|
||
|
||
-- IF(简单条件)
|
||
IF(condition, true_value, false_value)
|
||
|
||
-- NVL(空值替换)
|
||
NVL(col, default_value)
|
||
```
|
||
|
||
---
|
||
|
||
## 复杂类型操作
|
||
|
||
```sql
|
||
-- ARRAY 操作
|
||
array(val1, val2, ...) -- 创建数组
|
||
array_contains(arr, val) -- 判断是否包含
|
||
element_at(arr, idx) -- 取元素(idx从1开始)
|
||
arr[idx] -- 取元素(idx从0开始)
|
||
size(arr) -- 数组长度
|
||
array_join(arr, delimiter) -- 数组转字符串
|
||
sort_array(arr) -- 排序
|
||
array_distinct(arr) -- 去重
|
||
|
||
-- 展开(LATERAL VIEW + explode)
|
||
-- 展开数组
|
||
SELECT id, tag
|
||
FROM table
|
||
LATERAL VIEW explode(tags) t AS tag;
|
||
|
||
-- 展开数组带索引
|
||
SELECT id, pos, tag
|
||
FROM table
|
||
LATERAL VIEW posexplode(tags) t AS pos, tag;
|
||
|
||
-- 展开 Map
|
||
SELECT id, map_key, map_value
|
||
FROM table
|
||
LATERAL VIEW explode(props) m AS map_key, map_value;
|
||
|
||
-- MAP 操作
|
||
map(key1, val1, key2, val2) -- 创建 Map
|
||
str_to_map(str, delim1, delim2) -- 字符串转 Map
|
||
map_contains(map, key) -- 判断是否包含key
|
||
map_keys(map) -- 所有 key(返回数组)
|
||
map_values(map) -- 所有 value(返回数组)
|
||
size(map) -- Map大小
|
||
|
||
-- STRUCT 操作
|
||
named_struct('name1', val1, 'name2', val2) -- 创建结构体
|
||
struct_col.field_name -- 访问结构体字段
|
||
```
|
||
|
||
---
|
||
|
||
## 分区表操作
|
||
|
||
```sql
|
||
-- 创建分区表
|
||
CREATE TABLE target_table (
|
||
id BIGINT,
|
||
name STRING,
|
||
amount DECIMAL(18,2)
|
||
)
|
||
PARTITIONED BY (day_id STRING)
|
||
STORED AS ORC;
|
||
|
||
-- 静态分区写入
|
||
INSERT OVERWRITE TABLE target_table
|
||
PARTITION (day_id = '${day_id}')
|
||
SELECT id, name, amount FROM source_table;
|
||
|
||
-- 动态分区写入
|
||
SET hive.exec.dynamic.partition = true;
|
||
SET hive.exec.dynamic.partition.mode = nonstrict;
|
||
|
||
INSERT OVERWRITE TABLE target_table
|
||
PARTITION (day_id)
|
||
SELECT id, name, amount, day_id FROM source_table;
|
||
|
||
-- 分区管理
|
||
SHOW PARTITIONS target_table;
|
||
ALTER TABLE target_table ADD IF NOT EXISTS PARTITION (day_id = '2026-05-10');
|
||
ALTER TABLE target_table DROP IF EXISTS PARTITION (day_id = '2026-01-01');
|
||
|
||
-- MSCK REPAIR(恢复分区元数据)
|
||
MSCK REPAIR TABLE target_table;
|
||
```
|
||
|
||
---
|
||
|
||
## 与 Spark SQL 的主要差异
|
||
|
||
| 特性 | Spark SQL | Hive | 说明 |
|
||
|------|-----------|------|------|
|
||
| **LEFT SEMI JOIN** | ✅ 独立语法 | ✅ 支持(语义相同) | Hive 也可用 IN 子查询替代 |
|
||
| **LEFT ANTI JOIN** | ✅ 独立语法 | ✅ 支持(语义相同) | Hive 也可用 NOT IN 替代 |
|
||
| **CTE (WITH)** | ✅ 支持 | ✅ Hive 0.13+ 支持 | 都支持但 Hive 中推荐物化临时表 |
|
||
| **INSERT OVERWRITE** | ✅ 支持 | ✅ 支持 | 写法一致 |
|
||
| **MERGE INTO** | ✅ 支持 | ❌ 不支持 | Hive 不支持 |
|
||
| **UPDATE/DELETE** | ❌ 不支持 | 仅 ACID 表支持 | 普通 Hive 表不支持 |
|
||
| **collect_list/set** | ✅ 支持 | ✅ 支持 | 完全一致 |
|
||
| **LATERAL VIEW** | ✅ 支持 | ✅ 支持(Hive 原生) | Hive 首创的语法 |
|
||
| **分桶 JOIN** | 可优化 | 可优化(SMB JOIN) | Hive 分桶优化更成熟 |
|
||
| **日期格式** | `yyyy-MM-dd` | `yyyy-MM-dd` | 格式一致 |
|
||
| **临时表** | CREATE TEMP TABLE | CREATE TEMPORARY TABLE | 关键字略有不同 |
|
||
| **存储格式** | PARQUET/ORC | ORC/PARQUET/TEXTFILE | Hive 支持 TEXTFILE |
|
||
| **分区发现** | 自动 | 需 MSCK REPAIR 或 ALTER | Hive 需手动恢复 |
|
||
| **复杂类型** | 完整支持 | 完整支持 | 基本一致 |
|
||
| **窗口函数** | ✅ 完整支持 | ✅ 完整支持 | 语法一致 |
|
||
|
||
---
|
||
|
||
## SQL 生成规则
|
||
|
||
### 通用规则(所有引擎统一)
|
||
|
||
1. **禁止使用 CTE (WITH 子句)**,每个主要逻辑步骤必须物化为临时表
|
||
2. **先 DROP 再 CREATE**:`DROP TABLE IF EXISTS ...; CREATE TABLE ... AS SELECT ...;`
|
||
3. **禁止 `SELECT *`**,必须明确列出所有字段
|
||
4. 多表查询时所有表必须使用简短别名
|
||
5. 每个步骤前添加注释说明
|
||
6. **谓词下推**:过滤条件前置,JOIN 时在 WHERE 中一并添加过滤
|
||
7. 临时表命名:`${db_tmp_env}.tmp_{业务简称}_{步骤序号}`
|
||
|
||
### Hive 特有规则
|
||
|
||
1. 使用 `INSERT OVERWRITE TABLE ... PARTITION (...)` 写入目标表
|
||
2. 动态分区需先 `SET hive.exec.dynamic.partition = true;`
|
||
3. 分区列不能出现在表定义的列中(Hive 特有约束)
|
||
4. 支持 `collect_list` / `collect_set` 聚合
|
||
5. 支持 `LATERAL VIEW explode()` 展开数组
|
||
6. 日期函数:`date_format()`, `to_date()`, `date_add()`, `add_months()`(和 Spark 一致)
|
||
7. 时间范围筛选:
|
||
```sql
|
||
-- 日账期过滤
|
||
WHERE day_id = '${day_id}'
|
||
-- 最近N个月(月份格式 yyyyMM)
|
||
WHERE month_id >= date_format(add_months(to_date('${month_id}', 'yyyyMM'), -N), 'yyyyMM')
|
||
AND month_id < '${month_id}'
|
||
```
|
||
|
||
### SQL 脚本结构
|
||
|
||
```sql
|
||
-- =====================================================================
|
||
-- @SqlName: hive-D-SQL-{表名}
|
||
-- @Engine: hive
|
||
-- ...(头注释)
|
||
-- =====================================================================
|
||
|
||
-- Step01: {步骤描述}
|
||
DROP TABLE IF EXISTS ${db_tmp_env}.tmp_xxx_01;
|
||
CREATE TABLE ${db_tmp_env}.tmp_xxx_01 AS
|
||
SELECT ...;
|
||
|
||
-- Step02: {步骤描述}
|
||
DROP TABLE IF EXISTS ${db_tmp_env}.tmp_xxx_02;
|
||
CREATE TABLE ${db_tmp_env}.tmp_xxx_02 AS
|
||
SELECT ...;
|
||
|
||
-- 最后一步:写入目标表
|
||
INSERT OVERWRITE TABLE ${db_eda_env}.target_table
|
||
PARTITION (day_id = '${day_id}')
|
||
SELECT ...;
|
||
```
|