注意: 时态表 时态变函数Blink都 支持推荐使用 但是时态表函数不支持DDL 标准SQL 创建所以 可以使时态表 功能相近 并且时态表可以DDL 创建 使用时态表函数 只能使用TABLE API 去注册
package com.cn.sql.joins.temporaljoins;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
/**
* 时态表 Join
* 1 Syntax 语法
* SELECT [column_list]
* FROM table1 [AS <alias1>] --探针侧(普通表)
* [LEFT] JOIN table2 FOR SYSTEM_TIME AS OF table1.{ proctime | rowtime } [AS <alias2>] --构建侧(版本表)
* ON table1.column-name1 = table2.column-name1
* 2 定义:
* 基于事件时间的时态 Join
* 基于事件时间的时态表 join 使用(左侧输入/探针侧) 的 事件时间 去关联(右侧输入/构建侧) 版本表 对应的版本。
* 基于事件时间的时态表 join 仅支持关版本表或版本视图,版本表或版本视图只能是一个 changelog 流。
* 但是,Flink 支持将 append-only 流转换成 changelog 流,因此版本表也可以来自一个 append-only 流。
* 查看声明版本视图 获取更多的信息关于如何声明一张来自 append-only 流的版本表。
* 将事件时间作为时间属性时,可将 过去 时间属性与时态表一起使用。这允许对两个表中在相同时间点的记录执行 Join 操作。
* 与基于处理时间的时态 Join 相比,时态表不仅将构建侧记录的最新版本(是否最新由所定义的主键所决定)保存在 state 中,同时也会存储自上一个 watermarks 以来的所有版本(按时间区分)。
* 例如,在探针侧表新插入一条事件时间时间为 12:30:00 的记录,它将和构建侧表时间点为 12:30:00 的版本根据时态表的概念进行 Join 运算。
* 因此,新插入的记录仅与时间戳小于等于 12:30:00 的记录进行 Join 计算(由主键决定哪些时间点的数据将参与计算)。
* 通过定义事件时间,watermarks 允许 Join 运算不断向前滚动,丢弃不再需要的构建侧快照。因为不再需要时间戳更低或相等的记录。
* 3 注意
* 注意 1: 基于事件时间的时态表 Join 是通过左右两侧的 watermark 触发,请确保为 join 两侧的表设置了合适的 watermark。
* 注意 2: 基于事件时间的时态表 Join 的 join key 必须包含时态表的主键,例如:表 product_changelog 的主键 P.product_id 必须包含在 join 条件 O.product_id = P.product_id 中。
* 注意3: 为了保证关联的信息的准确型推荐使用事件事件去定义版本表 防止数据错乱
*/
public class TemporalJoins {
public static void main(String[] args) {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment Tenv = StreamTableEnvironment.create(env);
/* 声明一张版本表 也叫构建测*/
/*
* 基于事件时间的时态表 join 仅支持关版本表或版本视图,版本表或版本视图只能是一个 changelog 流。
* 我这里使用用CDC 也可以使用canal 输出到kafka但是必须是changelog 因为这样会有变更记录可查询
* */
Tenv.executeSql(
"CREATE TABLE `Data_Input` (\n" +
" id BIGINT,\n" +
" actor VARCHAR(20),\n" +
" alias VARCHAR(20),\n" +
" order_time VARCHAR(20),\n" +
" `ts` as TO_TIMESTAMP(order_time),\n" +
" WATERMARK FOR ts AS ts," +
" PRIMARY KEY (`id`) NOT ENFORCED\n" +
") WITH (\n" +
" 'connector' = 'mysql-cdc', -- 可选 'mysql-cdc' 和 'postgres-cdc'\n" +
" 'hostname' = 'localhost', -- 数据库的 IP\n" +
" 'port' = '3306', -- 数据库的访问端口\n" +
" 'username' = 'root', -- 数据库访问的用户名(需要提供 SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT, SELECT, RELOAD 权限)\n" +
" 'password' = 'root', -- 数据库访问的密码\n" +
" 'database-name' = 'zhou', -- 需要同步的数据库\n" +
" 'table-name' = 'mysqlcdc' -- 需要同步的数据表名\n" +
")");
/*声明一张普通表 也叫 探针测 */
Tenv.executeSql(
"CREATE TABLE currency_rates (\n" +
"id BIGINT ,\n" +
"state STRING ,\n" +
" order_time TIMESTAMP(3),\n" +
" WATERMARK FOR order_time AS order_time -- defines the necessary event time\n" +
") \n" +
"WITH ( \n" +
"'connector'='kafka',\n" +
"'properties.bootstrap.servers'='localhost:9092' ,\n" +
"'properties.group.id'='test01',\n" +
"'topic'='kafkaSS',\n" +
"'format'='csv'" +
")");
/*声明一张 输出控制台表*/
Tenv.executeSql(
"CREATE TABLE print (\n" +
"id BIGINT,\n" +
"ts TIMESTAMP(3),\n" +
"actor VARCHAR(20),\n" +
"alias VARCHAR(20)," +
"state STRING,\n" +
"order_time TIMESTAMP(3),\n" +
"PRIMARY KEY (`id`) NOT ENFORCED" +
")\n " +
"WITH (\n" +
"'connector'='print'" +
")\n");
//Tenv.executeSql("INSERT INTO print SELECT id,actor,alias,order_time FROM Data_Input");
/*查询语句 版本表关联 普通表 */
Tenv.executeSql("INSERT INTO print SELECT \n" +
" O.id,\n" +
" ts,\n" +
" actor,\n" +
" alias,\n" +
" state,\n" +
"O.order_time\n" +
"FROM currency_rates AS O\n" +
"LEFT JOIN Data_Input FOR SYSTEM_TIME AS OF O.order_time AS P\n" +
"ON O.id = P.id");
}
}