Flink SQL INSERT 语句单表写入、多表分流、分区覆盖与 StatementSet

1. INSERT 语句是干嘛的

INSERT 用于把查询结果或字面量数据写入目标表(sink 表)。在 Flink 里,执行 INSERT 会提交一个 Flink Job(流式作业通常是长期运行)。


2. Java 里怎么跑 INSERT:单条 executeSql vs 多条 StatementSet

2.1 单条 INSERT:executeSql 立即提交作业

executeSql() 执行 INSERT 会立刻提交 Job,并返回 TableResult,你可以通过它拿到 JobClient 查询状态。

java 复制代码
TableEnvironment tEnv = TableEnvironment.create(...);

// source & sink
tEnv.executeSql("CREATE TABLE Orders (`user` BIGINT, product VARCHAR, amount INT) WITH (...)");
tEnv.executeSql("CREATE TABLE RubberOrders(product VARCHAR, amount INT) WITH (...)");

// submit job immediately
TableResult r1 = tEnv.executeSql(
  "INSERT INTO RubberOrders " +
  "SELECT product, amount FROM Orders WHERE product LIKE '%Rubber%'"
);

System.out.println(r1.getJobClient().get().getJobStatus());

2.2 多条 INSERT:StatementSet.addInsertSql 延迟执行,一次 execute 提交

当你要把同一个源表数据分流写入多个 sink(比如 RubberOrders、GlassOrders),用 StatementSet 更合适:先 addInsertSql() 收集多条语句,最后 execute() 一次性提交。

java 复制代码
tEnv.executeSql("CREATE TABLE GlassOrders(product VARCHAR, amount INT) WITH (...)");

StatementSet stmtSet = tEnv.createStatementSet();

stmtSet.addInsertSql(
  "INSERT INTO RubberOrders SELECT product, amount FROM Orders WHERE product LIKE '%Rubber%'"
);
stmtSet.addInsertSql(
  "INSERT INTO GlassOrders SELECT product, amount FROM Orders WHERE product LIKE '%Glass%'"
);

TableResult r2 = stmtSet.execute();
System.out.println(r2.getJobClient().get().getJobStatus());

注意:addInsertSql() 每次只能接收一条 INSERT 语句(不要把多个 INSERT 拼一条字符串)。

3. INSERT INTO / INSERT OVERWRITE:追加 vs 覆盖

3.1 总体语法(Insert from Select)

sql 复制代码
[EXECUTE] INSERT { INTO | OVERWRITE } [catalog.][db.]table_name
  [PARTITION part_spec]
  [column_list]
  select_statement

3.2 INTO:追加写入(Append)

  • 不覆盖已有数据(或已有分区数据),新结果继续追加。

3.3 OVERWRITE:覆盖写入(Overwrite)

  • INSERT OVERWRITE 会覆盖目标表或目标分区已有数据。
  • 常用于离线批处理、重跑分区、或者"以最后一次跑出来的结果为准"的场景。

4. 分区写入:静态分区 vs 动态分区

假设目标表是分区表:

sql 复制代码
CREATE TABLE country_page_view (
  user STRING,
  cnt INT,
  date STRING,
  country STRING
)
PARTITIONED BY (date, country)
WITH (...);

4.1 写入静态分区(date/country 都固定)

sql 复制代码
INSERT INTO country_page_view PARTITION (date='2019-8-30', country='China')
SELECT user, cnt FROM page_view_source;

4.2 半动态分区(date 固定、country 每行决定)

sql 复制代码
INSERT INTO country_page_view PARTITION (date='2019-8-30')
SELECT user, cnt, country FROM page_view_source;

4.3 覆盖分区写入(静态/半动态都支持)

sql 复制代码
INSERT OVERWRITE country_page_view PARTITION (date='2019-8-30', country='China')
SELECT user, cnt FROM page_view_source;

INSERT OVERWRITE country_page_view PARTITION (date='2019-8-30')
SELECT user, cnt, country FROM page_view_source;

5. EXECUTE 关键字:显式执行(语义等价)

Flink 允许在 INSERT 前面加 EXECUTE,用于强调"我要执行这条语句",但语义上等价于不加。

sql 复制代码
EXECUTE INSERT INTO country_page_view PARTITION (date='2019-8-30', country='China')
SELECT user, cnt FROM page_view_source;

6. column_list:部分列写入(Partial Insert)怎么映射?

Flink 支持指定目标列列表,把 SELECT 的列按列表顺序写入指定列,未写到的列会被置为 NULL(前提:该列可空)。

例:表 T(a INT, b INT, c INT):

sql 复制代码
INSERT INTO T(c, b)
SELECT x, y FROM S;

含义是:

  • x 写入 c
  • y 写入 b
  • a 被置为 NULL(如果 a 允许为 NULL)

对 connector/sink 开发者:可以通过 DynamicTableSink.Context.getTargetColumns() 获取用户指定的目标列,决定如何处理"部分列更新"。

7. INSERT ... VALUES:直接插入字面量行

除了 INSERT INTO ... SELECT ...,也可以直接写 values:

sql 复制代码
[EXECUTE] INSERT { INTO | OVERWRITE } table_name
VALUES (val1, val2, ...), (val1, val2, ...);

示例:

sql 复制代码
CREATE TABLE students (name STRING, age INT, gpa DECIMAL(3, 2)) WITH (...);

INSERT INTO students
VALUES ('fred flintstone', 35, 1.28),
       ('barney rubble', 32, 2.32);

8. 一条 SQL 写多个表:EXECUTE STATEMENT SET

如果你在 SQL 层就想"一次提交多条 insert",可以用:

sql 复制代码
EXECUTE STATEMENT SET
BEGIN
  insert_statement;
  insert_statement;
END;

其中 insert_statement 可以是 INSERT ... SELECT 或 INSERT ... VALUES。

9. 生产实践建议(你放到博客结尾很加分)

  1. 多 sink 分流优先用 StatementSet:一次提交、共享规划,写法更稳。
  2. OVERWRITE 慎用:尤其是流式任务,确认 connector 对覆盖语义的支持与目标表期望行为。
  3. 分区写入要区分静态/动态:静态分区适合重跑;动态分区适合实时按维度落地。
  4. 部分列写入会把其它列写成 NULL:对非空列/主键列要提前约束,否则容易写入失败或产生脏数据。
相关推荐
白帽攻防录4 小时前
SRC 挖洞:Roundcube 预认证 SQL 注入深度复盘,CVE-2026-48842 preg_replace 转义绕过怎么打穿邮件系统
网络·数据库·sql·网络安全·sql注入
꯭自꯭闭꯭5 小时前
达梦SQL优化相关
linux·运维·数据库·sql
对空六课5 小时前
支持注意力分析的热力图工具有哪些?
前端·数据库·数据分析
南京码讯光电技术有限公司6 小时前
How to Design an Antenna System for an Industrial WiFi Module
数据库·人工智能
lusklusklusk7 小时前
Oracle数据库基础之2_体系结构
数据库·oracle
可乐ea7 小时前
从第一性原理构建 AI Agent:提示词、工具、技能与记忆全解剖
数据库·人工智能·工具调用·ai智能体·提示词工程·agent开发·智能体记忆
东方护航数据恢复(深圳)7 小时前
医疗案例:HIS/PACS 数据库页损坏修复,医院不停诊完成恢复【东方护航数据恢复深圳店】
数据库·数据恢复·医疗·二次开盘
lusklusklusk8 小时前
Oracle数据库基础之11_Duplicate和Dataguard和RAC
数据库·oracle
PHP实战开发录10 小时前
MySQL字段加索引为什么没变快
数据库·mysql·php·开发
红红谈说11 小时前
标签化推送与已读统计怎么做?一次通知链路的工程复盘
数据库·消息推送·数字乡村·集合运算·已读回执·标签体系·写入放大