# 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\ | 数组 | tags ARRAY\ | | MAP\ | 映射 | props MAP\ | | STRUCT\ | 结构体 | info STRUCT\ | --- ## 时间函数 ```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 ...; ```