321 lines
12 KiB
Markdown
321 lines
12 KiB
Markdown
# Apache Doris SQL 语法参考
|
||
|
||
## 数据类型
|
||
|
||
| 类型 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| BOOLEAN | 布尔 | active BOOLEAN |
|
||
| TINYINT | 1字节整数 | level TINYINT |
|
||
| SMALLINT | 2字节整数 | age SMALLINT |
|
||
| INT | 4字节整数 | count INT |
|
||
| BIGINT | 8字节整数 | id BIGINT |
|
||
| LARGEINT | 16字节整数 | hash_key LARGEINT |
|
||
| FLOAT | 4字节浮点 | score FLOAT |
|
||
| DOUBLE | 8字节浮点 | price DOUBLE |
|
||
| DECIMAL(p,s) | 定点数 | amount DECIMAL(18,2) |
|
||
| DATE | 日期 | birth_date DATE |
|
||
| DATETIME | 日期时间(精确到秒) | created_at DATETIME |
|
||
| CHAR(n) | 定长字符串 | code CHAR(10) |
|
||
| VARCHAR(n) | 变长字符串 | name VARCHAR(100) |
|
||
| STRING | 变长字符串(无长度限制) | description STRING |
|
||
| BITMAP | 位图(精确去重) | user_bitmap BITMAP |
|
||
| HLL | HyperLogLog(近似去重) | user_hll HLL |
|
||
| JSON | JSON 数据 | props JSON |
|
||
| ARRAY\<type\> | 数组 | tags ARRAY\<STRING\> |
|
||
| MAP\<k,v\> | 映射 | props MAP\<STRING,STRING\> |
|
||
| STRUCT\<field:type,...\> | 结构体 | info STRUCT\<id:INT,name:STRING\> |
|
||
|
||
---
|
||
|
||
## 时间函数
|
||
|
||
```sql
|
||
-- 当前时间
|
||
NOW() -- 当前日期时间
|
||
CURDATE() -- 当前日期
|
||
CURRENT_TIMESTAMP() -- 当前时间戳
|
||
|
||
-- 格式转换
|
||
DATE_FORMAT(date_col, '%Y-%m-%d') -- 日期格式化
|
||
DATE_FORMAT(datetime_col, '%Y-%m-%d %H:%i:%s') -- 时间格式化
|
||
STR_TO_DATE(str, '%Y-%m-%d') -- 字符串转日期
|
||
|
||
-- 日期计算
|
||
DATE_ADD(date_col, INTERVAL 7 DAY) -- 加7天
|
||
DATE_SUB(date_col, INTERVAL 7 DAY) -- 减7天
|
||
DATEDIFF(end_date, start_date) -- 日期差(天数)
|
||
TIMESTAMPDIFF(unit, start, end) -- 时间差(指定单位)
|
||
TIMESTAMPADD(unit, interval, datetime) -- 时间加
|
||
|
||
-- 日期提取
|
||
YEAR(date_col) -- 年
|
||
MONTH(date_col) -- 月
|
||
DAY(date_col) -- 日
|
||
HOUR(datetime_col) -- 时
|
||
MINUTE(datetime_col) -- 分
|
||
SECOND(datetime_col) -- 秒
|
||
QUARTER(date_col) -- 季度 (1-4)
|
||
WEEK(date_col) -- 年中第几周
|
||
DAYOFWEEK(date_col) -- 周几 (1=周日)
|
||
DAYOFYEAR(date_col) -- 年中第几天
|
||
|
||
-- Unix 时间戳
|
||
UNIX_TIMESTAMP() -- 当前 Unix 时间戳
|
||
UNIX_TIMESTAMP(datetime_col) -- 转换为 Unix 时间戳
|
||
FROM_UNIXTIME(timestamp) -- Unix 时间戳转时间字符串
|
||
FROM_UNIXTIME(timestamp, fmt) -- 带格式的转换
|
||
|
||
-- Doris 日期格式符(不同于 Spark)
|
||
-- %Y: 4位年, %m: 2位月, %d: 2位日
|
||
-- %H: 24小时制, %i: 分钟, %s: 秒
|
||
-- %j: 年中天数, %W: 周名
|
||
```
|
||
|
||
---
|
||
|
||
## 字符串函数
|
||
|
||
```sql
|
||
-- 常用函数
|
||
CONCAT(str1, str2, ...) -- 字符串拼接
|
||
CONCAT_WS('-', str1, str2, ...) -- 用分隔符拼接
|
||
LOWER(str) -- 转小写
|
||
UPPER(str) -- 转大写
|
||
TRIM(str) -- 去两端空格
|
||
LTRIM(str) -- 去左空格
|
||
RTRIM(str) -- 去右空格
|
||
LENGTH(str) -- 字符串长度
|
||
CHAR_LENGTH(str) -- 字符数(中文友好)
|
||
SUBSTRING(str, pos, len) -- 截取字符串(pos从1开始)
|
||
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) -- 正则提取(注意和 Spark 参数不同)
|
||
REGEXP_REPLACE(str, pattern, replacement) -- 正则替换
|
||
|
||
-- 分割
|
||
SPLIT_BY_STRING(str, delimiter) -- 分割(Doris 特有)
|
||
SPLIT_PART(str, delimiter, idx) -- 取分割后的第idx部分
|
||
|
||
-- 其他
|
||
INITCAP(str) -- 首字母大写
|
||
LPAD(str, len, pad) -- 左填充
|
||
RPAD(str, len, pad) -- 右填充
|
||
HEX(str) -- 转16进制
|
||
UNHEX(str) -- 16进制转字符串
|
||
```
|
||
|
||
---
|
||
|
||
## 聚合函数
|
||
|
||
```sql
|
||
-- 基础聚合
|
||
COUNT(*) -- 计数(含NULL行)
|
||
COUNT(col) -- 计数(不含NULL)
|
||
COUNT(DISTINCT col) -- 去重计数
|
||
SUM(col) -- 求和
|
||
AVG(col) -- 平均值
|
||
MIN(col) -- 最小值
|
||
MAX(col) -- 最大值
|
||
|
||
-- 集合聚合
|
||
GROUP_CONCAT(col SEPARATOR ',') -- 字符串聚合(类似 collect_list)
|
||
APPROX_COUNT_DISTINCT(col) -- 近似去重计数
|
||
|
||
-- 统计函数
|
||
VARIANCE(col) -- 方差
|
||
VAR_POP(col) -- 总体方差
|
||
VAR_SAMP(col) -- 样本方差
|
||
STDDEV(col) -- 标准差
|
||
STDDEV_POP(col) -- 总体标准差
|
||
STDDEV_SAMP(col) -- 样本标准差
|
||
|
||
-- Bitmap 精确去重(Doris 特有)
|
||
-- 用于 Aggregate Key 模型中定义为 BITMAP 的列
|
||
-- bitmap_union_count(bitmap_col) -- 精确去重计数
|
||
-- bitmap_union(bitmap_col) -- 合并 bitmap
|
||
-- bitmap_hash(col) -- 将值转为 bitmap(用于写入)
|
||
|
||
-- HLL 近似去重(Doris 特有)
|
||
-- hll_union_agg(hll_col) -- 近似去重计数
|
||
-- hll_cardinality(hll_col) -- 返回 HLL 基数
|
||
-- hll_hash(col) -- 将值转为 HLL(用于写入)
|
||
```
|
||
|
||
---
|
||
|
||
## 条件表达式
|
||
|
||
```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)
|
||
|
||
-- IFNULL(空值替换,等同 NVL)
|
||
IFNULL(col, default_value)
|
||
```
|
||
|
||
---
|
||
|
||
## JSON 函数
|
||
|
||
```sql
|
||
-- 解析与提取
|
||
JSON_PARSE(json_str) -- 解析 JSON 字符串
|
||
JSON_EXTRACT(json_str, '$.field') -- 提取 JSON 字段(返回 JSON 类型)
|
||
JSON_EXTRACT_STRING(json_str, '$.field') -- 提取 JSON 字段(返回 STRING)
|
||
JSON_EXTRACT_INT(json_str, '$.field') -- 提取 JSON 字段(返回 INT)
|
||
JSON_EXTRACT_DOUBLE(json_str, '$.field') -- 提取 JSON 字段(返回 DOUBLE)
|
||
JSON_EXTRACT_BOOL(json_str, '$.field') -- 提取 JSON 字段(返回 BOOLEAN)
|
||
|
||
-- 路径语法
|
||
-- $ : 根节点
|
||
-- $.field : 对象字段
|
||
-- $[0] : 数组索引
|
||
-- $.a.b : 嵌套字段
|
||
|
||
-- 构造
|
||
JSON_OBJECT('key1', val1, 'key2', val2) -- 构造 JSON 对象
|
||
JSON_ARRAY(val1, val2, ...) -- 构造 JSON 数组
|
||
|
||
-- 查询
|
||
JSON_LENGTH(json_str) -- JSON 长度
|
||
JSON_KEYS(json_str) -- JSON 所有 key
|
||
JSON_VALID(json_str) -- 是否合法 JSON
|
||
```
|
||
|
||
---
|
||
|
||
## ARRAY 函数
|
||
|
||
```sql
|
||
-- 创建
|
||
ARRAY(val1, val2, ...) -- 创建数组
|
||
|
||
-- 访问
|
||
array_contains(arr, val) -- 判断是否包含
|
||
element_at(arr, idx) -- 取元素(idx从1开始)
|
||
arr[idx] -- 取元素(idx从0开始)
|
||
|
||
-- 操作
|
||
SIZE(arr) -- 数组长度
|
||
ARRAY_JOIN(arr, delimiter) -- 数组转字符串
|
||
CONCAT(arr1, arr2) -- 数组拼接
|
||
|
||
-- 展开与排序
|
||
EXPLODE(arr) -- 展开数组为多行(LATERAL VIEW 中使用)
|
||
ARRAY_SORT(arr) -- 排序
|
||
ARRAY_DISTINCT(arr) -- 去重
|
||
```
|
||
|
||
---
|
||
|
||
## 与 Spark SQL 的主要差异
|
||
|
||
| 特性 | Spark SQL | Apache Doris | 说明 |
|
||
|------|-----------|-------------|------|
|
||
| **日期格式符** | `yyyy-MM-dd` | `%Y-%m-%d` | Doris 用 MySQL 风格格式符 |
|
||
| **当前时间** | `current_timestamp()` | `NOW()` 或 `CURRENT_TIMESTAMP()` | 都支持,Doris 偏好 NOW() |
|
||
| **日期加减** | `date_add(col, 7)` | `DATE_ADD(col, INTERVAL 7 DAY)` | Doris 需要 INTERVAL 语法 |
|
||
| **正则提取** | `regexp_extract(str, pattern, idx)` | `REGEXP_EXTRACT(str, pattern, idx)` | 参数名可能不同 |
|
||
| **LEFT SEMI JOIN** | ✅ 支持 | ❌ 不支持 | 用 IN 子查询替代 |
|
||
| **LEFT ANTI JOIN** | ✅ 支持 | ❌ 不支持 | 用 NOT IN / NOT EXISTS 替代 |
|
||
| **INSERT OVERWRITE** | ✅ 支持 | ✅ 2.0+ 支持 | 早期版本不支持 |
|
||
| **CTE (WITH)** | ✅ 支持 | ✅ 支持 | 都支持 |
|
||
| **MERGE INTO** | ✅ 支持 | ❌ 不支持 | Doris 用 UPSERT 替代 |
|
||
| **临时表链式处理** | ✅ 推荐 | ✅ 统一规范 | 编码规范层面统一禁止 CTE |
|
||
| **精确去重** | COUNT(DISTINCT) | COUNT(DISTINCT) 或 BITMAP | Doris BITMAP 性能更好 |
|
||
| **近似去重** | `approx_count_distinct` | HLL 类型 | Doris 内置 HLL 类型 |
|
||
| **UPDATE/DELETE** | ❌ 不支持 | ✅ 支持 | Doris 支持 DML |
|
||
| **UPSERT** | ❌ 不支持 | ❌ 不直接支持 | 用 Aggregate/Unique Key 模型替代 |
|
||
| **分页** | LIMIT(无OFFSET) | LIMIT + OFFSET | Doris 完整支持 |
|
||
| **JSON** | `get_json_object` | `JSON_EXTRACT_STRING` 等系列函数 | 函数名完全不同 |
|
||
| **collect_list/set** | ✅ 支持 | ❌ 不直接支持 | 用 GROUP_CONCAT 替代 |
|
||
| **LATERAL VIEW explode** | ✅ 支持 | ✅ 支持 | 语法兼容 |
|
||
|
||
---
|
||
|
||
## 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_{业务简称}_{步骤序号}`
|
||
|
||
### Doris 特有规则
|
||
|
||
1. 使用 `INSERT INTO` 写入目标表(Doris 2.0+ 也支持 `INSERT OVERWRITE`)
|
||
2. Aggregate Key 表自动合并相同 Key 的数据
|
||
3. Unique Key 表自动按主键去重,保留最新数据
|
||
4. 不支持 `LEFT SEMI JOIN` / `LEFT ANTI JOIN`,用 `IN` / `NOT IN` 替代
|
||
5. 精确去重推荐 `BITMAP`,近似去重推荐 `HLL`
|
||
6. 日期函数用 MySQL 风格:
|
||
- `DATE_FORMAT(col, '%Y-%m-%d')`(不是 `yyyy-MM-dd`)
|
||
- `DATE_ADD(col, INTERVAL 7 DAY)`(不是 `date_add(col, 7)`)
|
||
- `CURDATE()` / `NOW()`
|
||
7. 不支持 `collect_list` / `collect_set`,用 `GROUP_CONCAT` 替代
|
||
8. 时间范围筛选:
|
||
```sql
|
||
-- 日账期过滤
|
||
WHERE stat_date = '${day_id}'
|
||
-- 最近N个月
|
||
WHERE stat_date >= DATE_FORMAT(DATE_SUB(STR_TO_DATE('${month_id}', '%Y%m'), INTERVAL N MONTH), '%Y%m')
|
||
AND stat_date < '${month_id}'
|
||
```
|
||
|
||
### SQL 脚本结构
|
||
|
||
```sql
|
||
-- =====================================================================
|
||
-- @SqlName: doris-D-SQL-{表名}
|
||
-- @Engine: doris
|
||
-- ...(头注释)
|
||
-- =====================================================================
|
||
|
||
-- 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 INTO ${db_eda_env}.target_table
|
||
SELECT ...;
|
||
```
|