Apache Doris 的 INSERT INTO ... WITH AS(CTE)语法是支持的,但必须将 CTE 包裹在子查询中,或直接在 INSERT INTO ... SELECT 的 SELECT 部分使用,并建议显式指定 WITH LABEL。
- 标准写法 :
INSERT INTO target_table WITH LABEL label_name WITH cte_name AS (...) SELECT ... FROM cte_name; - 兼容写法 (若上述报错):
INSERT INTO target_table SELECT * FROM (WITH cte_name AS (...) SELECT ...) AS sub; - Doris 要求 CTE 必须作为
SELECT的一部分 ,不能独立于INSERT INTO ... SELECT之外使用; - **生产环境建议显式指定
WITH LABEL**,避免自动生成标签冲突; - CTE 支持多层定义(如
WITH cte1 AS (...), cte2 AS (SELECT ... FROM cte1)),但整个查询需在SELECT子句内; - 若启用
enable_insert_strict = true(默认),数据格式错误会导致整个插入失败。
示例:
INSERT INTO target_tbl WITH LABEL 'my_cte_label' WITH tmp AS (SELECT id, name FROM source_tbl WHERE status = 'active') SELECT id, UPPER(name) FROM tmp; ```:ml-citation{ref="11,12" appearance="aggregated" data="citationList"} 如遇语法错误,可改用子查询包裹 CTE: ```sql INSERT INTO target_tbl SELECT * FROM ( WITH cte AS (SELECT ... FROM ...) SELECT ... FROM cte ) AS sub;
sql
INSERT INTO target_tbl WITH LABEL 'my_cte_label' WITH tmp AS (SELECT id, name FROM source_tbl WHERE status = 'active') SELECT id, UPPER(name) FROM tmp; ```:ml-citation{ref="11,12" appearance="aggregated" data="citationList"}
如遇语法错误,可改用子查询包裹 CTE: ```sql INSERT INTO target_tbl SELECT * FROM ( WITH cte AS (SELECT ... FROM ...) SELECT ... FROM cte ) AS sub;
Doris 2.0+ 对 CTE 在 DML 中的支持更稳定,旧版本(如 1.x)可能存在限制,建议升级或测试验证。
具体案例:
sql
INSERT INTO cdn.edge_client_area_bandwidth_hour SELECT * FROM (
with crossSet as (SELECT
t.time as time,
CASE WHEN (n & 1) = 0 THEN CAST(t.productId AS STRING) ELSE 'all' END AS productId,
CASE WHEN (n & 2) = 0 THEN t.cp ELSE 'all' END AS cp,
CASE WHEN (n & 4) = 0 THEN t.domain ELSE 'all' END AS domain,
CASE WHEN (n & 8) = 0 THEN t.clientArea ELSE 'all' END AS clientArea,
CASE WHEN (n & 16) = 0 THEN t.ipProtocol ELSE 'all' END AS ipProtocol,
CASE WHEN (n & 32) = 0 THEN t.clientOperator ELSE 'all' END AS clientOperator,
CASE WHEN (n & 64) = 0 THEN t.provider ELSE 'all' END AS provider,
CASE WHEN (n & 128) = 0 THEN t.orderId ELSE 'all' END AS orderId,
CASE WHEN (n & 256) = 0 THEN t.sourceCode ELSE 'all' END AS sourceCode,
t.value
FROM cdn.edge_client_area_bandwidth_fivemin t
CROSS JOIN (SELECT number AS n FROM numbers("number"="512")) numbers WHERE t.time >= '2026-05-02 09:05:00' and t.time <= '2026-05-02 09:05:00'),
sumTab as (select crossSet.time, crossSet.productId, crossSet.cp, crossSet.domain, crossSet.clientArea, crossSet.ipProtocol, crossSet.clientOperator, crossSet.provider, crossSet.orderId, crossSet.sourceCode, sum(value) as sumValue from crossSet group by crossSet.time, crossSet.productId, crossSet.cp, crossSet.domain, crossSet.clientArea, crossSet.ipProtocol, crossSet.clientOperator, crossSet.provider, crossSet.orderId, crossSet.sourceCode)
select "2026-05-02 09:00:00", "bandwidthMinBiz", sumTab.cp, sumTab.productId, sumTab.provider, sumTab.clientArea, sumTab.domain, sumTab.clientOperator, sumTab.ipProtocol, sumTab.orderId, sumTab.sourceCode, max(sumValue) from sumTab group by sumTab.productId, sumTab.cp, sumTab.domain, sumTab.clientArea, sumTab.ipProtocol, sumTab.clientOperator, sumTab.provider, sumTab.orderId, sumTab.sourceCode
) AS sub;