3509964afc
* feat: rebuild flink sql parser * test: add sqls templates in stream app test cases
884 lines
34 KiB
SQL
884 lines
34 KiB
SQL
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 创建表
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
-- 执行创建临时表 DDL,不需要指定catalog.database
|
||
CREATE TABLE orders (
|
||
order_uid BIGINT,
|
||
product_id BIGINT,
|
||
price DECIMAL(32, 2),
|
||
order_time TIMESTAMP(3)
|
||
) WITH (
|
||
'connector' = 'datagen'
|
||
);
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 INSERT INTO
|
||
--********************************************************************--
|
||
-- 定义数据源表
|
||
CREATE TABLE server_logs (
|
||
client_ip STRING,
|
||
client_identity STRING,
|
||
userid STRING,
|
||
user_agent STRING,
|
||
log_time TIMESTAMP(3),
|
||
request_line STRING,
|
||
status_code STRING,
|
||
size INT
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.client_ip.expression' = '#{Internet.publicIpV4Address}',
|
||
'fields.client_identity.expression' = '-',
|
||
'fields.userid.expression' = '-',
|
||
'fields.user_agent.expression' = '#{Internet.userAgentAny}',
|
||
'fields.log_time.expression' = '#{date.past ''15'',''5'',''SECONDS''}',
|
||
'fields.request_line.expression' = '#{regexify ''(GET|POST|PUT|PATCH){1}''} #{regexify ''(/search\.html|/login\.html|/prod\.html|cart\.html|/order\.html){1}''} #{regexify ''(HTTP/1\.1|HTTP/2|/HTTP/1\.0){1}''}',
|
||
'fields.status_code.expression' = '#{regexify ''(200|201|204|400|401|403|301){1}''}',
|
||
'fields.size.expression' = '#{number.numberBetween ''100'',''10000000''}'
|
||
);
|
||
|
||
-- 定义结果表,实际应用中会选择 Kafka、JDBC 等作为结果表
|
||
CREATE TABLE client_errors (
|
||
log_time TIMESTAMP(3),
|
||
request_line STRING,
|
||
status_code STRING,
|
||
size INT
|
||
) WITH (
|
||
'connector' = 'stream-x'
|
||
);
|
||
|
||
-- 写入数据到结果表
|
||
INSERT INTO client_errors
|
||
SELECT
|
||
log_time,
|
||
request_line,
|
||
status_code,
|
||
size
|
||
FROM server_logs
|
||
WHERE
|
||
status_code SIMILAR TO '4[0-9][0-9]';
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 Statement Set
|
||
--********************************************************************--
|
||
-- 定义数据源表
|
||
CREATE TABLE server_logs (
|
||
client_ip STRING,
|
||
client_identity STRING,
|
||
userid STRING,
|
||
user_agent STRING,
|
||
log_time TIMESTAMP(3),
|
||
request_line STRING,
|
||
status_code STRING,
|
||
size INT,
|
||
WATERMARK FOR log_time AS log_time - INTERVAL '30' SECONDS
|
||
) WITH (
|
||
'connector' = 'faker', -- Faker 连接器仅在 VVR-4.0.12 及以上支持
|
||
'fields.client_ip.expression' = '#{Internet.publicIpV4Address}',
|
||
'fields.client_identity.expression' = '-',
|
||
'fields.userid.expression' = '-',
|
||
'fields.user_agent.expression' = '#{Internet.userAgentAny}',
|
||
'fields.log_time.expression' = '#{date.past ''15'',''5'',''SECONDS''}',
|
||
'fields.request_line.expression' = '#{regexify ''(GET|POST|PUT|PATCH){1}''} #{regexify ''(/search\.html|/login\.html|/prod\.html|cart\.html|/order\.html){1}''} #{regexify ''(HTTP/1\.1|HTTP/2|/HTTP/1\.0){1}''}',
|
||
'fields.status_code.expression' = '#{regexify ''(200|201|204|400|401|403|301){1}''}',
|
||
'fields.size.expression' = '#{number.numberBetween ''100'',''10000000''}'
|
||
);
|
||
|
||
-- 定义结果表1
|
||
CREATE TABLE aggregations1 (
|
||
`browser` STRING,
|
||
`status_code` STRING,
|
||
`end_time` TIMESTAMP(3),
|
||
`requests` BIGINT NOT NULL
|
||
) WITH (
|
||
'connector' = 'blackhole'
|
||
);
|
||
|
||
-- 定义结果表2
|
||
CREATE TABLE aggregations2 (
|
||
`browser` STRING,
|
||
`status_code` STRING,
|
||
`requests` BIGINT NOT NULL
|
||
) WITH (
|
||
'connector' = 'stream-x'
|
||
);
|
||
|
||
-- This is a shared view that will be used by both insert into statements
|
||
CREATE VIEW browsers AS
|
||
SELECT
|
||
REGEXP_EXTRACT(user_agent,'[^\/]+') AS browser,
|
||
status_code,
|
||
log_time
|
||
FROM server_logs;
|
||
|
||
-- 封装多个INSERT INTO语句到一个STATEMENT SET语句中
|
||
BEGIN STATEMENT SET;
|
||
-- 5min窗口粒度聚合
|
||
INSERT INTO aggregations1
|
||
SELECT
|
||
browser,
|
||
status_code,
|
||
TUMBLE_ROWTIME(log_time, INTERVAL '5' MINUTE) AS end_time,
|
||
COUNT(*) requests
|
||
FROM browsers
|
||
GROUP BY
|
||
browser,
|
||
status_code,
|
||
TUMBLE(log_time, INTERVAL '5' MINUTE);
|
||
-- 1h窗口粒度聚合
|
||
INSERT INTO aggregations2
|
||
SELECT
|
||
browser,
|
||
status_code,
|
||
COUNT(*) requests
|
||
FROM browsers
|
||
GROUP BY
|
||
browser,
|
||
status_code,
|
||
TUMBLE(log_time, INTERVAL '1' HOUR);
|
||
END;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 Watermark
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.doctor_sightings (
|
||
doctor STRING,
|
||
sighting_time TIMESTAMP(3),
|
||
-- 通过watermark把sighting_time标识为事件时间,定义最大的乱序时间:期望所有的记录在目击发生后的15秒内都到达。
|
||
WATERMARK FOR sighting_time AS sighting_time - INTERVAL '15' SECONDS
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.doctor.expression' = '#{dr_who.the_doctors}',
|
||
'fields.sighting_time.expression' = '#{date.past ''15'',''SECONDS''}'
|
||
);
|
||
|
||
SELECT
|
||
doctor,
|
||
-- 在滚动窗口中使用sighting_time字段
|
||
TUMBLE_ROWTIME(sighting_time, INTERVAL '1' MINUTE) AS sighting_time,
|
||
COUNT(*) AS sightings
|
||
FROM dt_catalog.dt_db.doctor_sightings
|
||
GROUP BY
|
||
TUMBLE(sighting_time, INTERVAL '1' MINUTE),
|
||
doctor;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 GROUP BY
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
-- 定义数据源表
|
||
CREATE TABLE dt_catalog.dt_db.server_logs (
|
||
client_ip STRING,
|
||
client_identity STRING,
|
||
userid STRING,
|
||
user_agent STRING,
|
||
log_time TIMESTAMP(3),
|
||
request_line STRING,
|
||
status_code STRING,
|
||
size INT
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.client_ip.expression' = '#{Internet.publicIpV4Address}',
|
||
'fields.client_identity.expression' = '-',
|
||
'fields.userid.expression' = '-',
|
||
'fields.user_agent.expression' = '#{Internet.userAgentAny}',
|
||
'fields.log_time.expression' = '#{date.past ''15'',''5'',''SECONDS''}',
|
||
'fields.request_line.expression' = '#{regexify ''(GET|POST|PUT|PATCH){1}''} #{regexify ''(/search\.html|/login\.html|/prod\.html|cart\.html|/order\.html){1}''} #{regexify ''(HTTP/1\.1|HTTP/2|/HTTP/1\.0){1}''}',
|
||
'fields.status_code.expression' = '#{regexify ''(200|201|204|400|401|403|301){1}''}',
|
||
'fields.size.expression' = '#{number.numberBetween ''100'',''10000000''}'
|
||
);
|
||
|
||
-- 采样user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A
|
||
-- 正则表达式: '[^\/]+' (匹配 '/' 之前的所有字符)
|
||
SELECT
|
||
REGEXP_EXTRACT(user_agent,'[^\/]+') AS browser,
|
||
status_code,
|
||
COUNT(*) AS cnt_status
|
||
FROM dt_catalog.dt_db.server_logs
|
||
-- 按浏览器和状态码两个维度统计日志数量
|
||
GROUP BY
|
||
REGEXP_EXTRACT(user_agent,'[^\/]+'),
|
||
status_code;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 滚动窗口聚合
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.server_logs (
|
||
client_ip STRING,
|
||
client_identity STRING,
|
||
userid STRING,
|
||
request_line STRING,
|
||
status_code STRING,
|
||
log_time AS PROCTIME() -- 使用当前系统处理时间作为表的时间字段
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.client_ip.expression' = '#{Internet.publicIpV4Address}',
|
||
'fields.client_identity.expression' = '-',
|
||
'fields.userid.expression' = '-',
|
||
'fields.log_time.expression' = '#{date.past ''15'',''5'',''SECONDS''}',
|
||
'fields.request_line.expression' = '#{regexify ''(GET|POST|PUT|PATCH){1}''} #{regexify ''(/search\.html|/login\.html|/prod\.html|cart\.html|/order\.html){1}''} #{regexify ''(HTTP/1\.1|HTTP/2|/HTTP/1\.0){1}''}',
|
||
'fields.status_code.expression' = '#{regexify ''(200|201|204|400|401|403|301){1}''}'
|
||
);
|
||
|
||
-- 按 window_start, window_end 维度计算每分钟窗口上不同的 ip 数量
|
||
SELECT window_start, window_end, COUNT(DISTINCT client_ip) AS ip_addresses
|
||
FROM TABLE(
|
||
-- 定义1min滑动窗口
|
||
TUMBLE(TABLE dt_catalog.dt_db.server_logs, DESCRIPTOR(log_time), INTERVAL '1' MINUTE))
|
||
GROUP BY window_start, window_end;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 滑动窗口聚合
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.bids (
|
||
bid_id STRING,
|
||
currency_code STRING,
|
||
bid_price DOUBLE,
|
||
transaction_time TIMESTAMP(3),
|
||
WATERMARK FOR transaction_time AS transaction_time - INTERVAL '5' SECONDS -- 定义事件时间,允许的最大窗口延迟为5s
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.bid_id.expression' = '#{Internet.UUID}',
|
||
'fields.currency_code.expression' = '#{regexify ''(EUR|USD|CNY)''}',
|
||
'fields.bid_price.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
|
||
'fields.transaction_time.expression' = '#{date.past ''30'',''SECONDS''}',
|
||
'rows-per-second' = '100'
|
||
);
|
||
|
||
-- 定义1min 的滑动窗口,每隔 30s 滚动一次
|
||
SELECT window_start, window_end, currency_code, ROUND(AVG(bid_price),2) AS MovingAverageBidPrice
|
||
FROM TABLE(
|
||
HOP(TABLE dt_catalog.dt_db.bids, DESCRIPTOR(transaction_time), INTERVAL '30' SECONDS, INTERVAL '1' MINUTE))
|
||
GROUP BY window_start, window_end, currency_code;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 累计窗口聚合
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
-- 商品销售订单表
|
||
CREATE TABLE dt_catalog.dt_db.orders (
|
||
order_id BIGINT, -- 订单ID
|
||
goods_id BIGINT, -- 商品ID
|
||
goods_sales DOUBLE, -- 商品销售额
|
||
order_time TIMESTAMP(3), -- 下单时间
|
||
WATERMARK FOR order_time AS order_time - INTERVAL '5' SECONDS -- 定义事件时间,允许的最大窗口延迟为5s
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.order_id.expression' = '#{number.numberBetween ''0'',''1000000000''}',
|
||
'fields.goods_id.expression' = '#{number.numberBetween ''0'',''1000000000''}',
|
||
'fields.goods_sales.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
|
||
'fields.order_time.expression' = '#{date.past ''30'',''SECONDS''}',
|
||
'rows-per-second' = '100'
|
||
);
|
||
|
||
-- 每分钟更新一次从零点开始截止到当前时刻的累计销售额
|
||
SELECT
|
||
window_start,
|
||
window_end,
|
||
SUM(goods_sales) AS cumulate_gmv -- 当天累计销售额
|
||
FROM TABLE(
|
||
-- 定义窗口最大长度为一天的累计窗口,窗口滚动步长为1分钟
|
||
CUMULATE(
|
||
TABLE dt_catalog.dt_db.orders,
|
||
DESCRIPTOR(order_time),
|
||
INTERVAL '1' MINUTES,
|
||
INTERVAL '1' DAY))
|
||
GROUP BY window_start, window_end;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 会话窗口聚合
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.server_logs (
|
||
client_ip STRING,
|
||
client_identity STRING,
|
||
userid STRING,
|
||
log_time TIMESTAMP(3),
|
||
request_line STRING,
|
||
status_code STRING,
|
||
WATERMARK FOR log_time AS log_time - INTERVAL '5' SECONDS -- 定义 watermark
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'rows-per-second' = '5',
|
||
'fields.client_ip.expression' = '#{Internet.publicIpV4Address}',
|
||
'fields.client_identity.expression' = '-',
|
||
'fields.userid.expression' = '#{regexify ''(morsapaes|knauf|sjwiesman){1}''}',
|
||
'fields.log_time.expression' = '#{date.past ''5'',''SECONDS''}',
|
||
'fields.request_line.expression' = '#{regexify ''(GET|POST|PUT|PATCH){1}''} #{regexify ''(/search\.html|/login\.html|/prod\.html|cart\.html|/order\.html){1}''} #{regexify ''(HTTP/1\.1|HTTP/2|/HTTP/1\.0){1}''}',
|
||
'fields.status_code.expression' = '#{regexify ''(200|201|204|400|401|403|301){1}''}'
|
||
);
|
||
|
||
SELECT
|
||
userid,
|
||
SESSION_START(log_time, INTERVAL '10' SECOND) AS session_beg,
|
||
SESSION_ROWTIME(log_time, INTERVAL '10' SECOND) AS session_end,
|
||
COUNT(request_line) AS request_cnt
|
||
FROM dt_catalog.dt_db.server_logs
|
||
WHERE status_code = '403'
|
||
GROUP BY
|
||
userid,
|
||
-- 会话窗口的最大空闲间隔为10s,当10s内该窗口没有接收到新的请求,会关闭当前窗口
|
||
SESSION(log_time, INTERVAL '10' SECOND);
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 OVER窗口聚合
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.temperature_measurements (
|
||
measurement_time TIMESTAMP(3),
|
||
city STRING,
|
||
temperature FLOAT,
|
||
WATERMARK FOR measurement_time AS measurement_time - INTERVAL '15' SECONDS -- 定义时间属性字段,OVER窗口排序时使用
|
||
) WITH (
|
||
'connector' = 'faker', -- Faker 连接器仅在 VVR-4.0.12 及以上支持
|
||
'fields.measurement_time.expression' = '#{date.past ''15'',''SECONDS''}',
|
||
'fields.temperature.expression' = '#{number.numberBetween ''0'',''50''}',
|
||
'fields.city.expression' = '#{regexify ''(Chicago|Munich|Berlin|Portland|Hangzhou|Seatle|Beijing|New York){1}''}'
|
||
);
|
||
|
||
SELECT
|
||
measurement_time,
|
||
city,
|
||
temperature,
|
||
AVG(CAST(temperature AS FLOAT)) OVER last_minute AS avg_temperature_minute, -- 计算平均值
|
||
MAX(temperature) OVER last_minute AS min_temperature_minute, -- 计算最大值
|
||
MIN(temperature) OVER last_minute AS max_temperature_minute, -- 计算最小值
|
||
STDDEV(CAST(temperature AS FLOAT)) OVER last_minute AS stdev_temperature_minute -- 计算标准差
|
||
FROM dt_catalog.dt_db.temperature_measurements
|
||
WINDOW last_minute AS ( -- 定义1min时间间隔的OVER窗口,按城市粒度分区,温度测量值排序,每个元素都会触发一次计算
|
||
PARTITION BY city
|
||
ORDER BY measurement_time
|
||
RANGE BETWEEN INTERVAL '1' MINUTE PRECEDING AND CURRENT ROW
|
||
);
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 级联窗口聚合
|
||
--********************************************************************--
|
||
CREATE TEMPORARY TABLE server_logs (
|
||
log_time TIMESTAMP(3),
|
||
client_ip STRING,
|
||
client_identity STRING,
|
||
userid STRING,
|
||
request_line STRING,
|
||
status_code STRING,
|
||
size INT,
|
||
WATERMARK FOR log_time AS log_time - INTERVAL '15' SECONDS -- 定义watermark
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.log_time.expression' = '#{date.past ''15'',''5'',''SECONDS''}',
|
||
'fields.client_ip.expression' = '#{Internet.publicIpV4Address}',
|
||
'fields.client_identity.expression' = '-',
|
||
'fields.userid.expression' = '-',
|
||
'fields.request_line.expression' = '#{regexify ''(GET|POST|PUT|PATCH){1}''} #{regexify ''(/search\.html|/login\.html|/prod\.html|cart\.html|/order\.html){1}''} #{regexify ''(HTTP/1\.1|HTTP/2|/HTTP/1\.0){1}''}',
|
||
'fields.status_code.expression' = '#{regexify ''(200|201|204|400|401|403|301){1}''}',
|
||
'fields.size.expression' = '#{number.numberBetween ''100'',''10000000''}'
|
||
);
|
||
|
||
-- 1min聚合结果表
|
||
CREATE TEMPORARY TABLE avg_request_size_1m (
|
||
window_start TIMESTAMP(3),
|
||
window_end TIMESTAMP(3),
|
||
avg_size BIGINT
|
||
) WITH (
|
||
'connector' = 'blackhole'
|
||
);
|
||
|
||
-- 5min聚合结果表
|
||
CREATE TEMPORARY TABLE avg_request_size_5m (
|
||
window_start TIMESTAMP(3),
|
||
window_end TIMESTAMP(3),
|
||
avg_size BIGINT
|
||
) WITH (
|
||
'connector' = 'blackhole'
|
||
);
|
||
|
||
-- 1min窗口查询结果
|
||
CREATE VIEW server_logs_window_1m AS
|
||
SELECT
|
||
TUMBLE_START(log_time, INTERVAL '1' MINUTE) AS window_start,
|
||
TUMBLE_ROWTIME(log_time, INTERVAL '1' MINUTE) AS window_end,
|
||
SUM(size) AS total_size,
|
||
COUNT(*) AS num_requests
|
||
FROM server_logs
|
||
GROUP BY
|
||
TUMBLE(log_time, INTERVAL '1' MINUTE);
|
||
|
||
-- 基于1min窗口查询结果,进行5min粒度窗口聚合
|
||
CREATE VIEW server_logs_window_5m AS
|
||
SELECT
|
||
TUMBLE_START(window_end, INTERVAL '5' MINUTE) AS window_start,
|
||
TUMBLE_ROWTIME(window_end, INTERVAL '5' MINUTE) AS window_end,
|
||
SUM(total_size) AS total_size,
|
||
SUM(num_requests) AS num_requests
|
||
FROM server_logs_window_1m
|
||
GROUP BY
|
||
TUMBLE(window_end, INTERVAL '5' MINUTE);
|
||
|
||
BEGIN STATEMENT SET;
|
||
-- 写入结果到1min窗口粒度结果表
|
||
INSERT INTO avg_request_size_1m SELECT
|
||
window_start,
|
||
window_end,
|
||
total_size / num_requests AS avg_size
|
||
FROM server_logs_window_1m;
|
||
|
||
-- 写入结果到5min窗口粒度结果表
|
||
INSERT INTO avg_request_size_5m SELECT
|
||
window_start,
|
||
window_end,
|
||
total_size / num_requests AS avg_size
|
||
FROM server_logs_window_5m;
|
||
END;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 去重
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.orders (
|
||
id INT,
|
||
order_time AS CURRENT_TIMESTAMP,
|
||
WATERMARK FOR order_time AS order_time - INTERVAL '5' SECONDS
|
||
)
|
||
WITH (
|
||
'connector' = 'datagen',
|
||
'rows-per-second'='10',
|
||
'fields.id.kind'='random',
|
||
'fields.id.min'='1',
|
||
'fields.id.max'='100'
|
||
);
|
||
|
||
-- 对于每个order_id,按事件时间去重,只保留最新时间的记录即可实现去重
|
||
SELECT
|
||
order_id,
|
||
order_time
|
||
FROM (
|
||
SELECT id AS order_id,
|
||
order_time,
|
||
-- 按事件时间升序排序
|
||
ROW_NUMBER() OVER (PARTITION BY id ORDER BY order_time) AS rownum
|
||
FROM dt_catalog.dt_db.orders)
|
||
WHERE rownum = 1; -- 只取排名第一的记录,去重是Top-N的一种特例
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 Top-N
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.spells_cast (
|
||
wizard STRING,
|
||
spell STRING
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.wizard.expression' = '#{harry_potter.characters}',
|
||
'fields.spell.expression' = '#{harry_potter.spells}'
|
||
);
|
||
|
||
-- 找出每个巫师最喜欢的两个法术
|
||
SELECT wizard, spell, times_cast
|
||
FROM (
|
||
SELECT *,
|
||
ROW_NUMBER() OVER (PARTITION BY wizard ORDER BY times_cast DESC) AS row_num -- 按法术次数降序排序
|
||
FROM (SELECT wizard, spell, COUNT(*) AS times_cast FROM dt_catalog.dt_db.spells_cast GROUP BY wizard, spell) -- 计算每个巫师施展的各种法术的次数
|
||
)
|
||
WHERE row_num <= 2;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 窗口Top-N
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.orders (
|
||
bidtime TIMESTAMP(3),
|
||
price DOUBLE,
|
||
item STRING,
|
||
supplier STRING,
|
||
WATERMARK FOR bidtime AS bidtime - INTERVAL '5' SECONDS -- 定义watermark
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.bidtime.expression' = '#{date.past ''30'',''SECONDS''}',
|
||
'fields.price.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
|
||
'fields.item.expression' = '#{Commerce.productName}',
|
||
'fields.supplier.expression' = '#{regexify ''(Alice|Bob|Carol|Alex|Joe|James|Jane|Jack)''}',
|
||
'rows-per-second' = '100'
|
||
);
|
||
|
||
-- 取出销售排名前三的供应商
|
||
SELECT *
|
||
FROM (
|
||
-- 按窗口时间分区,按价格降序排序
|
||
SELECT *, ROW_NUMBER() OVER (PARTITION BY window_start, window_end ORDER BY price DESC) AS rownum
|
||
FROM (
|
||
-- 计算每个窗口内各个供应商的销售额
|
||
SELECT window_start, window_end, supplier, SUM(price) AS price, COUNT(*) AS cnt
|
||
FROM TABLE(
|
||
TUMBLE(TABLE dt_catalog.dt_db.orders, DESCRIPTOR(bidtime), INTERVAL '10' MINUTES))
|
||
GROUP BY window_start, window_end, supplier
|
||
)
|
||
)
|
||
WHERE rownum <= 3;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 模式检测CEP
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.subscriptions (
|
||
id STRING,
|
||
user_id INT,
|
||
type STRING,
|
||
start_date TIMESTAMP(3),
|
||
end_date TIMESTAMP(3),
|
||
payment_expiration TIMESTAMP(3),
|
||
proc_time AS PROCTIME()
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.id.expression' = '#{Internet.uuid}',
|
||
'fields.user_id.expression' = '#{number.numberBetween ''1'',''50''}',
|
||
'fields.type.expression'= '#{regexify ''(basic|premium|platinum){1}''}',
|
||
'fields.start_date.expression' = '#{date.past ''30'',''DAYS''}',
|
||
'fields.end_date.expression' = '#{date.future ''15'',''DAYS''}',
|
||
'fields.payment_expiration.expression' = '#{date.future ''365'',''DAYS''}'
|
||
);
|
||
|
||
SELECT *
|
||
FROM dt_catalog.dt_db.subscriptions
|
||
MATCH_RECOGNIZE ( -- 按user_id分区,按处理时间proc_time升序排序
|
||
PARTITION BY user_id
|
||
ORDER BY proc_time
|
||
MEASURES
|
||
LAST(PREMIUM.type) AS premium_type,
|
||
AVG(TIMESTAMPDIFF(DAY,PREMIUM.start_date,PREMIUM.end_date)) AS premium_avg_duration,
|
||
BASIC.start_date AS downgrade_date
|
||
AFTER MATCH SKIP PAST LAST ROW
|
||
--模式: 一个或多个‘premium‘或’platinum‘订阅事件
|
||
--对于相同的'user_id',后面跟着一个'basic'订阅事件
|
||
PATTERN (PREMIUM+ BASIC)
|
||
DEFINE PREMIUM AS PREMIUM.type IN ('premium','platinum'),
|
||
BASIC AS BASIC.type = 'basic');
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 Regular Join
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.NOC (
|
||
agent_id STRING,
|
||
codename STRING
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.agent_id.expression' = '#{regexify ''(1|2|3|4|5){1}''}',
|
||
'fields.codename.expression' = '#{superhero.name}',
|
||
'number-of-rows' = '10'
|
||
);
|
||
|
||
CREATE TABLE dt_catalog.dt_db.RealNames (
|
||
agent_id STRING,
|
||
name STRING
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.agent_id.expression' = '#{regexify ''(1|2|3|4|5){1}''}',
|
||
'fields.name.expression' = '#{Name.full_name}',
|
||
'number-of-rows' = '10'
|
||
);
|
||
|
||
-- 使用agent_id作为两张表关联的条件,左右两边任何一张表来了新数据都会触发join动作
|
||
SELECT
|
||
name,
|
||
codename
|
||
FROM dt_catalog.dt_db.NOC t1
|
||
INNER JOIN dt_catalog.dt_db.RealNames t2 ON t1.agent_id = t2.agent_id;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 Interval Join
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.orders (
|
||
id INT,
|
||
order_time AS TIMESTAMPADD(DAY, CAST(FLOOR(RAND()*(1-5+1)+5)*(-1) AS INT), CURRENT_TIMESTAMP)
|
||
) WITH (
|
||
'connector' = 'datagen',
|
||
'rows-per-second'='10',
|
||
'fields.id.kind'='sequence',
|
||
'fields.id.start'='1',
|
||
'fields.id.end'='1000'
|
||
);
|
||
|
||
CREATE TABLE dt_catalog.dt_db.shipments (
|
||
id INT,
|
||
order_id INT,
|
||
shipment_time AS TIMESTAMPADD(DAY, CAST(FLOOR(RAND()*(1-5+1)) AS INT), CURRENT_TIMESTAMP)
|
||
) WITH (
|
||
'connector' = 'datagen',
|
||
'rows-per-second'='5',
|
||
'fields.id.kind'='random',
|
||
'fields.id.min'='0',
|
||
'fields.order_id.kind'='sequence',
|
||
'fields.order_id.start'='1',
|
||
'fields.order_id.end'='1000'
|
||
);
|
||
|
||
-- order表的每条数据会与shipments表过去三天至当前时刻时间范围内的数据进行join
|
||
SELECT
|
||
o.id AS order_id,
|
||
o.order_time,
|
||
s.shipment_time,
|
||
TIMESTAMPDIFF(DAY,o.order_time,s.shipment_time) AS day_diff
|
||
FROM dt_catalog.dt_db.orders o
|
||
JOIN dt_catalog.dt_db.shipments s ON o.id = s.order_id
|
||
WHERE
|
||
-- 时间 join 条件:shipments.shipment_time - INTERVAL '3' DAY <= orders.order_time < shipments.shipment_time
|
||
o.order_time BETWEEN s.shipment_time - INTERVAL '3' DAY AND s.shipment_time;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 时态表Join
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
-- 使用主键约束和watermark来定义一张版本表,这张表可以是一个cdc表、upsert类型的kafka topic等
|
||
CREATE TABLE dt_catalog.dt_db.currency_rates (
|
||
`currency_code` STRING,
|
||
`eur_rate` DECIMAL(6,4),
|
||
`rate_time` TIMESTAMP(3),
|
||
WATERMARK FOR `rate_time` AS rate_time - INTERVAL '15' SECONDS, -- 定义事件时间
|
||
PRIMARY KEY (currency_code) NOT ENFORCED -- 定义主键
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.currency_code.expression' = '#{Currency.code}',
|
||
'fields.eur_rate.expression' = '#{Number.randomDouble ''4'',''0'',''10''}',
|
||
'fields.rate_time.expression' = '#{date.past ''15'',''SECONDS''}',
|
||
'rows-per-second' = '100'
|
||
);
|
||
|
||
-- 这是一个append-only类型的动态表,需要定义watermk
|
||
CREATE TABLE dt_catalog.dt_db.transactions (
|
||
`id` STRING,
|
||
`currency_code` STRING,
|
||
`total` DECIMAL(10,2),
|
||
`transaction_time` TIMESTAMP(3),
|
||
WATERMARK FOR `transaction_time` AS transaction_time - INTERVAL '30' SECONDS --定义watermark
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.id.expression' = '#{Internet.UUID}',
|
||
'fields.currency_code.expression' = '#{Currency.code}',
|
||
'fields.total.expression' = '#{Number.randomDouble ''2'',''10'',''1000''}',
|
||
'fields.transaction_time.expression' = '#{date.past ''30'',''SECONDS''}',
|
||
'rows-per-second' = '100'
|
||
);
|
||
|
||
-- 当左右两张表的watermark对齐时,才会触发join动作,左右两张表都需要定义watermark
|
||
SELECT
|
||
t.id,
|
||
t.total * c.eur_rate AS total_eur,
|
||
t.total,
|
||
c.currency_code,
|
||
t.transaction_time
|
||
FROM dt_catalog.dt_db.transactions t
|
||
-- transactions表每条记录都与currency_rates表transaction_time时刻的汇率进行join
|
||
JOIN dt_catalog.dt_db.currency_rates FOR SYSTEM_TIME AS OF t.transaction_time AS c
|
||
-- 指定join key
|
||
ON t.currency_code = c.currency_code;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL 快速入门示例 维表Join
|
||
-- 该模版仅支持使用"执行"功能。如需"提交"运行,需要您增加 INSERT 相关逻辑
|
||
--********************************************************************--
|
||
CREATE TABLE dt_catalog.dt_db.subscriptions (
|
||
id STRING,
|
||
user_id INT,
|
||
type STRING,
|
||
start_date TIMESTAMP(3),
|
||
end_date TIMESTAMP(3),
|
||
payment_expiration TIMESTAMP(3),
|
||
proc_time AS PROCTIME() -- 这里需要定义处理时间属性
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.id.expression' = '#{Internet.uuid}',
|
||
'fields.user_id.expression' = '#{number.numberBetween ''1'',''50''}',
|
||
'fields.type.expression'= '#{regexify ''(basic|premium|platinum){1}''}',
|
||
'fields.start_date.expression' = '#{date.past ''30'',''DAYS''}',
|
||
'fields.end_date.expression' = '#{date.future ''365'',''DAYS''}',
|
||
'fields.payment_expiration.expression' = '#{date.future ''365'',''DAYS''}'
|
||
);
|
||
|
||
-- 定义维表,为了示例能直接运行,这里使用faker 作为维表,实际应用中一般会使用JDBC、Redis、Hbase等作为维表
|
||
CREATE TABLE dt_catalog.dt_db.users (
|
||
user_id INT PRIMARY KEY, -- 定义主键
|
||
user_name VARCHAR(255) NOT NULL,
|
||
age INT NOT NULL
|
||
) WITH (
|
||
'connector' = 'faker',
|
||
'fields.user_id.expression' = '#{number.numberBetween ''1'',''10''}',
|
||
'fields.user_name.expression' = '#{regexify ''(ron|jark|danny){1}''}',
|
||
'fields.age.expression' = '#{number.numberBetween ''1'',''30''}'
|
||
);
|
||
|
||
SELECT
|
||
id AS subscription_id,
|
||
type AS subscription_type,
|
||
age AS user_age,
|
||
CASE
|
||
WHEN age < 18 THEN 1
|
||
ELSE 0
|
||
END AS is_minor
|
||
FROM dt_catalog.dt_db.subscriptions usub
|
||
-- subscriptions每条记录都使用当前系统时间与维表users中的最新数据进行join
|
||
JOIN dt_catalog.dt_db.users FOR SYSTEM_TIME AS OF usub.proc_time AS u
|
||
-- 指定join key
|
||
ON usub.user_id = u.user_id;
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL ODS 层
|
||
-- 实际应用中,该任务应该是一个采集任务,源表为RDB
|
||
--********************************************************************--
|
||
CREATE TABLE source_table (
|
||
account_number STRING,
|
||
channel_id INT,
|
||
account_open_datetime TIMESTAMP(3)
|
||
) WITH (
|
||
'connector' = 'faker', -- 使用 Flink Faker Connector
|
||
'fields.account_number.expression' = '#{Finance.iban}', -- 随机生成银行账号
|
||
'fields.channel_id.expression' = '#{number.numberBetween ''1'',''4''}', -- 渠道ID随机生成1到3之间的数字
|
||
'fields.account_open_datetime.expression' = '#{date.past ''15'',''5'',''SECONDS''}' -- 过去15天的日期,每5秒一条数据
|
||
);
|
||
|
||
-- 定义结果表,实际应用中应选择 Kafka等作为结果表
|
||
CREATE TABLE sink_table (
|
||
account_number STRING,
|
||
channel_id INT,
|
||
account_open_datetime TIMESTAMP(3)
|
||
) WITH (
|
||
'connector' = 'stream-x'
|
||
);
|
||
|
||
-- 写入数据到结果表
|
||
INSERT INTO sink_table SELECT * FROM source_table
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL DWD 层
|
||
-- 实际应用中,源表为 ODS TOPIC
|
||
--********************************************************************--
|
||
CREATE TABLE source_table (
|
||
account_number STRING,
|
||
channel_id INT,
|
||
account_open_datetime TIMESTAMP(3)
|
||
) WITH (
|
||
'connector' = 'faker', -- 使用 Flink Faker Connector
|
||
'fields.account_number.expression' = '#{Finance.iban}', -- 随机生成银行账号
|
||
'fields.channel_id.expression' = '#{number.numberBetween ''1'',''4''}', -- 渠道ID随机生成1到3之间的数字
|
||
'fields.account_open_datetime.expression' = '#{date.past ''15'',''5'',''SECONDS''}' -- 过去15天的日期,每5秒一条数据
|
||
);
|
||
|
||
-- 定义维表,实际应用中应选择RDB作为维表
|
||
CREATE TABLE dim_table (
|
||
channel_id INT,
|
||
channel_name STRING,
|
||
PRIMARY KEY (channel_id,channel_name) NOT ENFORCED
|
||
) WITH (
|
||
'connector' = 'faker', -- 使用 Flink Faker Connector
|
||
'fields.channel_id.expression' = '#{number.numberBetween ''1'',''4''}', -- 渠道ID随机生成1到3之间的数字
|
||
'fields.channel_name.expression' = '#{app.name}' -- 渠道名称
|
||
);
|
||
|
||
-- 定义结果表,实际应用中应选择 Kafka等作为结果表
|
||
CREATE TABLE sink_table (
|
||
account_number STRING,
|
||
channel_id INT,
|
||
channel_name STRING,
|
||
account_open_datetime TIMESTAMP(3)
|
||
) WITH (
|
||
'connector' = 'stream-x'
|
||
);
|
||
|
||
-- 写入数据到结果表
|
||
INSERT INTO sink_table
|
||
SELECT
|
||
s1.account_number,
|
||
s1. channel_id ,
|
||
d1.channel_name,
|
||
s1.account_open_datetime
|
||
FROM source_table s1
|
||
left JOIN dim_table d1 ON s1.channel_id=d1.channel_id
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL DWS 层
|
||
-- 实际应用中,源表为DWD TOPIC
|
||
--********************************************************************--
|
||
CREATE TABLE source_table (
|
||
account_number STRING,
|
||
channel_id INT,
|
||
channel_name STRING,
|
||
account_open_datetime TIMESTAMP(3)
|
||
) WITH (
|
||
'connector' = 'faker', -- 使用 Flink Faker Connector
|
||
'fields.account_number.expression' = '#{Finance.iban}', -- 随机生成银行账号
|
||
'fields.channel_id.expression' = '#{number.numberBetween ''1'',''4''}', -- 渠道ID随机生成1到3之间的数字
|
||
'fields.channel_name.expression' = '#{app.name}' ,-- 渠道名称
|
||
'fields.account_open_datetime.expression' = '#{date.past ''15'',''5'',''SECONDS''}' -- 过去15天的日期,每5秒一条数据
|
||
);
|
||
DROP TABLE source_table
|
||
SELECT * FROM source_table
|
||
|
||
-- 定义结果表,实际应用中应选择Kafka作为结果表
|
||
CREATE TABLE sink_table (
|
||
channel_id STRING,
|
||
open_date STRING,
|
||
cnt INT
|
||
) WITH (
|
||
'connector' = 'stream-x'
|
||
);
|
||
DROP TABLE sink_table
|
||
SELECT * FROM sink_table
|
||
|
||
-- 写入数据到结果表
|
||
INSERT INTO sink_table
|
||
SELECT
|
||
channel_id,
|
||
DATE_FORMAT(account_open_datetime,'yyyy-MM-dd'),
|
||
count(account_number)
|
||
FROM source_table
|
||
GROUP BY channel_id,DATE_FORMAT(account_open_datetime,'yyyy-MM-dd')
|
||
|
||
|
||
--********************************************************************--
|
||
-- Flink SQL ADS 层
|
||
-- 实际应用中,源表为DWS TOPIC
|
||
--********************************************************************--
|
||
CREATE TABLE source_table (
|
||
channel_id STRING,
|
||
open_time TIMESTAMP(3),
|
||
cnt INT
|
||
) WITH (
|
||
'connector' = 'faker', -- 使用 Flink Faker Connector
|
||
'fields.channel_id.expression' = '#{number.numberBetween ''1'',''4''}', -- 渠道ID随机生成1到3之间的数字
|
||
'fields.open_time.expression' = '#{Date.future ''15'',''5'',''SECONDS''}' ,-- 日期
|
||
'fields.cnt.expression' = '#{number.numberBetween ''1'',''100000000''}'-- 数量
|
||
);
|
||
|
||
-- 实际应用中,结果表为RDB
|
||
CREATE TABLE sink_table (
|
||
open_date STRING,
|
||
cnt INT
|
||
) WITH (
|
||
'connector' = 'stream-x'
|
||
);
|
||
|
||
-- 写入数据到结果表
|
||
INSERT INTO sink_table
|
||
SELECT DATE_FORMAT(open_time,'yyyy-MM-dd'),count(1); |