本文旨在收集整理ODPS开发中入门及进阶级知识,尽可能涵盖大多ODPS开发问题,成为一本mini百科全书,后续也会持续更新。希望通过笔者的梳理和理解,帮助刚接触ODPS开发的同学快速上手。
本文为该系列第一篇:入门篇。
笔者不才,有任何错误纰漏,欢迎大家指正。
基础功能介绍
▐ 功能分类
一般来说,数据开发包括了以下几个类型:
▐ MaxCompute功能
在此,我们重点介绍一下其中MaxCompute模块(MaxCompute是适用于数据分析场景的企业级SaaS模式云数据仓库)的功能:
基础SQL
▐ DDL
具体语句1:
--创建新表。
create [external] table [if not exists] <table_name>
[primary key (<pk_col_name>, <pk_col_name2>),(<col_name> <data_type>
[not null] [default <default_value>] [comment <col_comment>], ...)]
[comment <table_comment>]
[partitioned by (<col_name> <data_type> [comment <col_comment>], ...)]
--用于创建聚簇表时设置表的Shuffle和Sort属性。
[clustered by | range clustered by (<col_name> [, <col_name>, ...])
[sorted by (<col_name> [asc | desc] [, <col_name> [asc | desc] ...])] into <number_of_buckets> buckets]
--仅限外部表。
[stored by StorageHandler]
--仅限外部表。
[with serdeproperties (options)]
--仅限外部表。
[location <osslocation>]
--指定表为Transactional1.0表,后续可以对该表执行更新或删除表数据操作,但是Transactional表有部分使用限制,请根据需求创建。
[tblproperties("transactional"="true")]
--指定表为Transactional2.0表,后续可以做upsert,增量查询,time-travel等操作
[tblproperties ("transactional"="true" [, "write.bucket.num" = "N", "acid.data.retain.hours"="hours"...])] [lifecycle <days>]
;
-------------------------------------------------------------------
--例子:
CREATE TABLE IF NOT EXISTS xxx.xxxx_xxxx_xxxx_hh
(
xxxxx STRING COMMENT '商品'
,xxxxx STRING COMMENT '名字'
)
COMMENT 'xxx表'
PARTITIONED BY
(
ds STRING COMMENT 'yyyymmddhh'
)
LIFECYCLE 7
;
参数说明:
external:可选。表示创建的表为外部表。
if not exists:可选。如果不指定if not exists选项而存在同名表,会报错。
table_name:必填。表名。
primary key(pk):可选。表的主键。
col_name:可选,表的列名。
col_comment:可选。列的注释内容。
data_type:可选。列的数据类型。
not null:可选。禁止该列的值为NULL。default_value:可选。指定列的默认值。
table_comment:可选。表注释内容。
lifecycle:可选。表的生命周期。
partitioned by (<col_name> <data_type> [comment <col_comment>], ...:可选。指定分区表的分区字段。
具体语句2:修改表的所有人
alter table <table_name> changeowner to <new_owner>;
--------------------------------------------------------
--例子
--将表test1的所有人修改为ALIYUN$xxx@aliyun.com
alter table test1 changeowner to 'ALIYUN$xxx@aliyun.com';
--将表test1的所有人修改为名称为ram_test的RAM用户
alter table test1 changeowner to 'RAM$13xxxxxxxxxxx:ram_test';
参数说明:
table_name:必填。待修改Owner的表名。
new_owner:必填。修改后的Owner账号。如果要修改Owner为RAM用户,格式为:RAM$<UID>:<ram_name>,其中UID为阿里云账号的账号ID,ram_name为RAM用户显示名称。
具体语句3:修改表的注释
alter table <table_name> set comment '<new_comment>';
--------------------------------------------------------
--例子
alter table sale_detail set comment 'new coments for table sale_detail';
参数说明:
table_name:必填。待修改注释的表的名称。
new_comment:必填。修改后的注释名称。
具体语句4:修改表的修改时间
alter table <table_name> touch;
--------------------------------------------------------
--例子
alter table sale_detail touch;
参数说明:
table_name:必填。待修改表的修改时间的表名称。
具体语句5:重命名表
alter table <table_name> rename to <new_table_name>;
--------------------------------------------------------
--例子
alter table sale_detail rename to sale_detail_rename;
参数说明:
table_name:必填。待修改名称的表。
new_table_name:必填。修改后的表名称。如果已存在与new_table_name同名的表,会返回报错。
具体语句6:删除表
drop table [if exists] <table_name>;
--------------------------------------------------------
--例子
drop table if exists sale_detail;
参数说明:
if exists:可选。如果不指定if exists且表不存在,则返回异常。如果指定if exists,无论表是否存在,均返回成功。
table_name:必填。待删除的表名。
具体语句7:查看表或视图信息
--查看表或视图信息。
desc <table_name|view_name> [partition (<pt_spec>)];
--查看外部表、聚簇表或Transactional表信息。也可以查看内部表的扩展信息。
desc extended <table_name>;
--------------------------------------------------------
--例子
desc test1;
参数说明:
table_name:必填。待查看表的名称。
view_name:必填。待查看视图的名称。
pt_spec:可选。待查看分区表的指定分区。
extended:如果表为外部表、聚簇表或Transactional表,需要包含此参数。
具体语句8:查看分区信息
desc <table_name> partition (<pt_spec>);
--------------------------------------------------------
--例子
--查询分区表sale_detail的分区信息。
desc sale_detail partition (xxxx_date='201310',region='beijing');
参数说明:
table_name:必填。待查看分区信息的分区表名称。
pt_spec:必填。待查看的分区信息。
具体语句9:查看建表语句
show create table <table_name>;
--------------------------------------------------------
--例子
--查看表sale_detail的建表语句。
show create table sale_detail;
参数说明:
table_name:必填。待查看建表语句的表的名称。
具体语句10:列出所有分区
show partitions <table_name>;
--------------------------------------------------------
--例子
--列出sale_detail中的所有分区。
show partitions sale_detail;
参数说明:
table_name:必填。待查看分区信息的分区表名称。
具体语句11:清空列数据
ALTER TABLE <table_name>
[partition ( <pt_spec>[, <pt_spec>....] )]
CLEAR COLUMN column1[, column2, column3, ...]
[without touch];
参数说明:
table_name:将要执行清空列数据的表名称。
column1 , column2...:将要被清空数据的列名称。
partition:指定分区。
pt_spec:分区描述。
without touch:表示不更新LastDataModifiedTime。
具体语句12:复制表
clone table <[<src_project_name>.]<src_table_name>> [partition(<pt_spec>), ...]
to <[<dest_project_name>.]<dest_table_name>> [if exists [overwrite | ignore]] ;
----------------------------------------------------------------------------
--例子
--复制表数据。
clone table xxxx_detail partition (xxxx_date='2013', region='china') to xxxx_detail_clone if exists overwrite;
参数说明:
src_project_name:可选。源表所属MaxCompute项目名称。
src_table_name:必填。源表名称。
pt_spec:可选。源表的分区信息。
dest_project_name:可选。
dest_table_name:必填。目标表名称。
▐ DML
具体语句1:插入或覆写数据
--插入:直接向表或静态分区中插入数据,可以在insert语句中直接指定分区值,将数据插入指定的分区。如果您需要插入少量测试数据,可以配合VALUES使用。
--覆写:先清空表或静态分区中的原有数据,再向表或静态分区中插入数据。
insert {into|overwrite} table <table_name> [partition (<pt_spec>)] [(<col_name> [,<col_name> ...)]]
<select_statement>
from <from_statement>
[zorder by <zcol_name> [, <zcol_name> ...]];
----------------------------------------------------------------------------
--例子
--向源表追加数据。其中:insert into table table_name可以简写为insert into table_name,但insert overwrite table table_name不可以省略table关键字。
insert into xxxx_detail partition (xxxx_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
--执行insert overwrite命令向表xxxx_detail_insert中覆写数据,调整select子句中列的顺序。
insert overwrite table xxxx_detail_insert partition (xxxx_date='2013', region='china')
select xxxx_id, xxxx_name, xxxx_price from xxxx_detail;
参数说明:
table_name:必填。需要插入数据的目标表名称。
pt_spec:可选。需要插入数据的分区信息。
col_name:可选。需要插入数据的目标表的列名称。
select_statement:必填。select子句,从源表中查询需要插入目标表的数据。
from_statement:必填。from子句,表示数据来源。
zorder by <zcol_name> [, <zcol_name> ...]:可选。向表或分区写入数据时,支持根据指定的一列或多列,把排序列数据相近的行排列在一起,提升查询时的过滤性能,在一定程度上降低存储成本。
具体语句2:插入或覆写动态分区数据
--在使用MaxCompute SQL处理数据时,分区列的值在select子句中提供,系统自动根据分区列的值将数据插入到相应分区。
insert {into|overwrite} table <table_name> partition (<ptcol_name>[, <ptcol_name> ...])
<select_statement> from <from_statement>;
----------------------------------------------------------------------------
--例子
--指定一级分区,将数据插入目标表。
insert overwrite table sale_detail_dypart partition (sale_date='2013', region)
select shop_name,customer_id,total_price,region from sale_detail;
--将源表sale_detail中的数据插入到目标表sale_detail_dypart。
insert overwrite table sale_detail_dypart partition (sale_date, region)
select shop_name,customer_id,total_price,sale_date,region from sale_detail;
参数说明:
table_name:必填。需要插入数据的目标表名。
ptcol_name:必填。目标表分区列的名称。
select_statement:必填。select子句,从源表中查询需要插入目标表的数据。
from_statement:必填。from子句,表示数据来源。例如,源表名称。
具体语句3:更新或删除数据
--删除操作:用于删除Transactional或Delta Table表中满足指定条件的单行或多行数据。
delete from <table_name> [where <where_condition>];
--清空列数据:将不再使用的列数据从磁盘删除并置NULL,从而达到降低存储成本的目的。
ALTER TABLE <table_name>
[partition ( <pt_spec>[, <pt_spec>....] )]
CLEAR COLUMN column1[, column2, column3, ...]
[without touch];
--更新操作:用于将Transactional表或Delta Table表中行对应的单列或多列数据更新为新值。
--方式1
update <table_name> set <col1_name> = <value1> [, <col2_name> = <value2> ...] [WHERE <where_condition>];
--方式2
update <table_name> set (<col1_name> [, <col2_name> ...]) = (<value1> [, <value2> ...])[WHERE <where_condition>];
--方式3
UPDATE <table_name>
SET <col1_name> = <value1> [ , <col2_name> = <value2> , ... ]
[ FROM <additional_tables> ]
[ WHERE <where_condition> ]
参数说明:
table_name:必填。
where_condition:可选。WHERE子句,用于筛选满足条件的数据。
partition:指定分区,若未指定,则表示操作所有分区。
pt_spec:分区描述。
without touch:表示不更新LastDataModifiedTime。
col1_name、col2_name:待修改行对应的列名称。
value1、value2:至少更新一个列值。修改后的新值。
where_condition:可选。WHERE子句,用于筛选满足条件的数据。
additional_tables:可选,from子句。
具体语句4:merge into
merge into <target_table> as <alias_name_t> using <source expression|table_name> as <alias_name_s>
--从on开始对源表和目标表的数据进行关联判断。
on <boolean expression1>
--when matched…then指定on的结果为True的行为。多个when matched…then之间的数据无交集。
when matched [and <boolean expression2>] then update set <set_clause_list>
when matched [and <boolean expression3>] then delete
--when not matched…then指定on的结果为False的行为。
when not matched [and <boolean expression4>] then insert values <value_list>
----------------------------------------------------------------------------
--例子
--执行merge into操作,对符合on条件的数据用源表的数据对目标表进行更新操作,对不符合on条件并且源表中满足event_type为I的数据插入目标表。命令示例如下:
merge into acid_address_book_base1 as t using tmp_table1 as s
on s.id = t.id and t.year='2020' and t.month='08' and t.day='20' and t.hour='16'
when matched then update set t.first_name = s.first_name, t.last_name = s.last_name, t.phone = s.phone
when not matched and (s._event_type_='I') then insert values(s.id, s.first_name, s.last_name,s.phone,'2020','08','20','16');
参数说明:
target_table:必填。目标表名称,必须是实际存在的表。
alias_name_t:必填。目标表的别名。
source expression|table_name:必填。关联的源表名称、视图或子查询。
alias_name_s:必填。关联的源表、视图或子查询的别名。
boolean expression1:必填。BOOLEAN类型判断条件,判断结果必须为True或False。
boolean expression2:可选。update、delete、insert操作相应的BOOLEAN类型判断条件。
set_clause_list:当出现update操作时必填。
value_list:当出现insert操作时必填。
具体语句5:Values
--insert … values
insert into table <table_name>
[partition (<pt_spec>)][(<col1_name> ,<col2_name>,...)]
values (<col1_value>,<col2_value>,...),(<col1_value>,<col2_value>,...),...
--values table
values (<col1_value>,<col2_value>,...),(<col1_value>,<col2_value>,...),<table_name> (<col1_name> ,<col2_name>,...)...
参数说明:
table_name:必填。待插入数据的表名称。
pt_spec:可选。需要插入数据的目标分区信息。
col_name:可选。需要插入数据的目标列名称。
col_value:可选。目标表中列对应的列值。
具体语句6:Load
--将Hologres、OSS、Amazon Redshift、BigQuery外部存储的CSV格式或其他开源格式数据导入MaxCompute的表或表的分区。
{load overwrite|into} table <table_name> [partition (<pt_spec>)]
from location <external_location>
stored by <StorageHandler>
[with serdeproperties (<Options>)];
----------------------------------------------------------------------------
--例子
load overwrite table xxxx_data_csv_load
from
location 'oss://oss-cn-hangzhou-internal.aliyuncs.com/mc-test/data_location/'
stored by 'com.aliyun.odps.CsvStorageHandler'
with serdeproperties (
'odps.properties.rolearn'='acs:ram::xxxxx:role/aliyunodpsdefaultrole', --AliyunODPSDefaultRole的ARN信息,可通过RAM角色管理页面获取。
'odps.text.option.delimiter'=','
);
参数说明:
table_name:必填。需要插入数据的目标表名称。
pt_spec:可选。需要插入数据的目标表分区信息。
external_location:必填。指定读取外部存储数据的OSS目录。
StorageHandler:必填。指定内置的StorageHandler名称。
Options:可选。指定外部表相关参数。
具体语句7:Unload
--将MaxCompute的数据导出至OSS、Hologres外部存储,OSS支持以CSV格式或其他开源格式存储数据。
unload from {<select_statement>|<table_name> [partition (<pt_spec>)]}
into
location <external_location>
stored by <StorageHandler>
[with serdeproperties ('<property_name>'='<property_value>',...)];
----------------------------------------------------------------------------
--例子
--控制导出文件个数:设置单个Worker读取MaxCompute表数据的大小,单位为MB。由于MaxCompute表有压缩,导出到OSS的数据一般会膨胀4倍左右。
set odps.stage.mapper.split.size=256;
--导出数据。
unload from sale_detail partition (sale_date='2013',region='china')
into
location 'oss://oss-cn-hangzhou-internal.aliyuncs.com/mc-unload/data_location'
stored by 'com.aliyun.odps.TsvStorageHandler'
with serdeproperties ('odps.properties.rolearn'='acs:ram::139699392458****:role/AliyunODPSDefaultRole', 'odps.text.option.gzip.output.enabled'='true');
参数说明:
select_statement:select查询子句,
table_name、pt_spec:使用表名称或表名称加分区名称的方式指定需要导出的数据。
external_location:必填。
StorageHandler:必填。指定内置的StorageHandler名称。
<property_name>'='<property_value>':可选。property_name为属性名称,property_value为属性值。
具体语句8:Explain
--分析查询语句或表结构来分析性能瓶颈
explain <dml query>;
----------------------------------------------------------------------------
--例子
explain
select a.customer_id as ashop, sum(a.total_price) as ap,count(b.total_price) as bp
from (select * from sale_detail_jt where sale_date='2013' and region='china') a
inner join (select * from sale_detail where sale_date='2013' and region='china') b
on a.customer_id=b.customer_id
group by a.customer_id
order by a.customer_id
limit 10;
参数说明:
dml query:必填。select语句。
具体语句9:公用表表达式
--临时命名结果集,用于简化SQL,可以更好地提高SQL语句的可读性与执行效率
with
<cte_name> as
(
<cte_query>
)
[,<cte_name2> as
(
<cte_query2>
)
,……]
----------------------------------------------------------------------------
--例子
with
a as (select * from src where key is not null),
b as (select * from src2 where value > 0),
c as (select * from src3 where value > 0),
d as (select a.key, b.value from a join b on a.key=b.key),
e as (select a.key,c.value from a left outer join c on a.key=c.key and c.key is not null)
insert overwrite table srcp partition (p='abc')
select * from d union all select * from e;
参数说明:
cte_name:必填。CTE的名称,不能与当前with子句中的其他CTE的名称相同。查询中任何使用到cte_name标识符的地方,均指CTE。
cte_query:必填。一个select语句。select的结果集用于填充CTE。
▐ DQL
-
SELECT语句
1. SELECT语法
[with <cte>[, ...] ]
SELECT [all | distinct] <SELECT_expr>[, <except_expr>][, <replace_expr>] ...
from <table_reference>
[where <where_condition>]
[group by {<col_list>|rollup(<col_list>)}]
[having <having_condition>]
[window <window_clause>]
[order by <order_condition>]
[distribute by <distribute_condition> [sort by <sort_condition>]|[ cluster by <cluster_condition>] ]
[limit <number>]
下面将介绍SELECT命令格式及如何实现嵌套查询、分组查询、排序等操作。
2. SELECT语序
--语法顺序
from <table_reference>
[where <where_condition>]
[group by <col_list>]
[having <having_condition>]
[window <window_name> AS (<window_definition>)]
[qualify <expression>]
select [all | distinct] <select_expr>, <select_expr>, ...
[order by <order_condition>]
[distribute by <distribute_condition> [sort by <sort_condition>] ]
[limit <number>]
场景1:from->where->group by->having->select->order by->limit
场景2:from->where->select->distribute by->sort by
3. WITH子句
with
A as (SELECT 1 as C),
B as (SELECT * from A)
SELECT * from B;
在同一WITH子句中的CTE必须具有唯一的名字。
在WITH子句中定义的CTE仅对在同一WITH子句中的其他CTE可以使用。
4. 列表达式
----------------------------------------------------------------------------
--例子
--读取表xxxx_detail的列shop_name
SELECT xxxx_name from xxxx_detail;
--查询表xxxx_detail中region列数据,如果有重复值时仅显示一条。
SELECT distinct region from xxxx_detail;
--选出xxxx_detail表中列名不为xxxx_name的所有列
SELECT `(xxxx_name)?+.+` from xxxx_detail;
--去重多列时,distinct的作用域是SELECT的列集合,不是单个列。
SELECT distinct region, xxxx_date from xxxx_detail;
用列名指定要读取的列。
用星号(*)代表查询所有的列。
可以使用正则表达式。
在选取的列名前可以使用distinct去掉重复字段,只返回去重后的值。
5. 排除列
--读取xxxx_detail表的数据,并排除region列的数据。
----------------------------------------------------------------------------
--例子
SELECT * except(region) from xxxx_detail;
当希望读取表内大多数列的数据,同时要排除表中少数列的数据时。
表示读取表数据时会排除指定列(col1、col2)的数据。
6. WHERE
--配合关系运算符,筛选满足指定条件的数据。关系运算符包含:
>、<、=、>=、<=、<>
like、rlike
in、not in
between…and
----------------------------------------------------------------------------
--例子
SELECT *
from xxxx_detail
where xxxx_date >= '2008' and xxxx_date <= '2014';
--等价于如下语句。
SELECT *
from xxxx_detail
where xxxx_date between '2008' and '2014';
where子句为过滤条件。如果表是分区表,可以实现列裁剪。
7. GROUP BY
----------------------------------------------------------------------------
--例子
--直接使用输入表列名region作为group by的列,即以region值分组
SELECT region from xxxx_detail group by region;
--以region值分组,返回每一组的销售额总量。
SELECT sum(xxxx_price) from xxxx_detail group by region;
--以region值分组,返回每一组的region值(组内唯一)及销售额总量。
SELECT region, sum (xxxx_price) from xxxx_detail group by region;
group by操作优先级高于SELECT操作,因此group by的取值是SELECT输入表的列名或由输入表的列构成的表达式。需要注意的是:
group by取值为正则表达式时,必须使用列的完整表达式。
SELECT语句中没有使用聚合函数的列必须出现在GROUP BY中。
8. HAVING
----------------------------------------------------------------------------
--例子
--为直观展示数据呈现效果,向sale_detail表中追加数据。
insert into sale_detail partition (sale_date='2014', region='shanghai')
values ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5);
--使用having子句配合聚合函数实现过滤。
SELECT region,sum(total_price) from sale_detail
group by region
having sum(total_price)<305;
通常HAVING子句与聚合函数一起使用,实现过滤。
9. ORDER BY
----------------------------------------------------------------------------
--例子
--查询表xxxx_detail的信息,并按照xxxx_price升序排列前2条。
SELECT * from xxxx_detail order by xxxx_price limit 2;
--将表xxx_detail按照xxxx_price升序排序后,输出从第3行开始的3行数据。
SELECT xxxx_id,xxxx_price from xxxx_detail order by xxxx_price limit 3 offset 2;
默认对数据进行升序排序,如果降序排序,需要使用desc关键字。
order by默认要求带limit数据行数限制,没有limit会返回报错。
10. DISTRIBUTE BY哈希分片
----------------------------------------------------------------------------
--例子
--查询表xxxx_detail中的列region值并按照region值进行哈希分片。
SELECT region from xxxx_detail distribute by region;
--等价于如下语句。
SELECT region as r from xxxx_detail distribute by region;
SELECT region as r from xxxx_detail distribute by r;
distribute by控制Map(读数据)的输出在Reducer中是如何划分的,如果不希望Reducer的内容存在重叠,或需要对同一分组的数据一起处理,可以使用distribute by来保证同组数据分发到同一个Reducer中。
11. SORT BY局部排序
----------------------------------------------------------------------------
--例子
--查询表xxxx_detail中的列region和xxxx_price的值并按照region值进行哈希分片,然后按照xxxx_price对哈希分片结果进行局部升序排序。
SELECT region,xxxx_price from xxxx_detail distribute by region sort by xxxx_price;
--查询表xxxx_detail中的列region和xxxx_price的值并按照region值进行哈希分片,然后按照xxxx_price对哈希分片结果进行局部降序排序。
SELECT region,xxxx_price from xxxx_detail distribute by region sort by xxxx_price desc;
--如果sort by语句前没有distribute by,sort by会对每个Reduce中的数据进行局部排序。
SELECT region,xxxx_price from xxxx_detail sort by xxxx_price desc;
sort by默认对数据进行升序排序,如果降序排序,需要使用desc关键字。
如果sort by语句前有distribute by,sort by会对distribute by的结果按照指定的列进行排序。
12. LIMIT限制输出行数
SELECT * FROM xxxxx.xxxx_xxxx_xxxx
WHERE ds = 20240520
LIMIT 100;
limit <number>中的number是常数,用于限制输出行数,取值范围为int32位取值范围。
-
子查询
1. 基础子查询
--格式1
select <select_expr> from (<select_statement>) [<sq_alias_name>];
--格式2
select (<select_statement>) from <table_name>;
普通查询操作的对象是目标表,但是查询的对象也可以是另一个select语句,这种查询为子查询。在from子句中,子查询可以被当作一张表,与其他表或子查询进行join操作。
2. IN SUBQUERY
--in subquery与left semi join用法类似
--格式一
select<select_expr1>from<table_name1>where<select_expr2>
in(select<select_expr3>from<table_name2>);
--等效于leftsemijoin如下语句。
select<select_expr1>from<table_name1><alias_name1>leftsemijoin<table_name2><alias_name2>
on<alias_name1>.<select_expr2>=<alias_name2>.<select_expr3>;
--格式二
select<select_expr1>from<table_name1>where<select_expr2>
in(select<select_expr3>from<table_name2>where
<table_name1>.<col_name>=<table_name2>.<col_name>);
----------------------------------------------------------------------------
--例子
set odps.sql.allow.fullscan=true;
select * from xxxx_detail where xxxx_price in (select xxxx_price from shop);
set odps.sql.allow.fullscan=true;
select * from xxxx_detail where xxxx_price
in (select xxxx_price from shop where xxxx_id = shop.xxxx_id);
select_expr1:必填。格式为col1_name, col2_name, 正则表达式,...,表示待查询的普通列、分区列或正则表达式。
table_name1、table_name2:必填。表的名称。
select_expr2、select_expr3:必填。表示table_name1和table_name2互相映射的列名。
col_name:必填。表的列名。
3. NOT IN SUBQUERY
--如果查询目标表的指定列名中有任意一行为NULL,则not in表达式值为NULL,导致where条件不成立,无数据返回
select <select_expr1> from <table_name1> where <select_expr2> not in (select <select_expr2> from <table_name2>);
--等效于left anti join如下语句。
select <select_expr1> from <table_name1> <alias_name1>
left anti join <table_name2> <alias_name2> on <alias_name1>.<select_expr1> = <alias_name2>.<select_expr2>;
----------------------------------------------------------------------------
--例子
--创建一张新表shop1并追加数据。
create table shop1 as select xxxx_name,xxxx_id,xxxx_price from xxxx_detail;
insert into shop1 values ('s8','c1',100.1);
select * from shop1 where xxxx_name not in (select xxxx_name from xxxx_detail);
set odps.sql.allow.fullscan=true;
select * from shop1 where xxxx_name not in (select xxxx_name from xxxx_detail where xxxx_id = shop1.xxxx_id);
select_expr1:必填。格式为col1_name, col2_name, 正则表达式,...,表示待查询的普通列、分区列或正则表达式。
table_name1、table_name2:必填。表的名称。
select_expr2、select_expr3:必填。表示table_name1和table_name2互相映射的列名。
col_name:必填。表的列名。
4. EXISTS SUBQUERY
--使用exists subquery时,当子查询中有至少一行数据时,返回True,否则返回False。
select <select_expr> from <table_name1> where exists
(select <select_expr> from <table_name2>
where <table_name2_colname> = <table_name1>.<colname>
);
----------------------------------------------------------------------------
--例子
set odps.sql.allow.fullscan=true;
select * from xxxx_detail where exists
(select * from shop where customer_id = xxxx_detail.xxxx_id);
--等效于以下语句。
select * from xxxx_detail a left semi join shop b on a.xxxx_id = b.xxxx_id;
select_expr:必填。格式为col1_name, col2_name, 正则表达式,...,表示待查询的普通列、分区列或正则表达式。
table_name1、table_name2:必填。表的名称。
col_name:必填。表的列名。
5. NOT EXISTS SUBQUERY
--当子查询中无数据时,返回True,否则返回False
select <select_expr> from <table_name1> where not exists
(select <select_expr> from <table_name2> where <table_name2_colname> = <table_name1>.<colname>);
----------------------------------------------------------------------------
--例子
set odps.sql.allow.fullscan=true;
select * from xxxx_detail where not exists (select * from shop where xxxx_name = xxxx_detail.xxxx_name);
--等效于以下语句。
select * from xxxx_detail a left anti join shop b on a.shop_name = b.xxxx_name;
select_expr:必填。格式为col1_name, col2_name, 正则表达式,...,表示待查询的普通列、分区列或正则表达式。
table_name1、table_name2:必填。表的名称。
col_name:必填。表的列名。
6. SCALAR SUBQUERY
--当子查询的输出结果为单行单列时,可以做为标量使用,即可以参与标量运算。
select <select_expr> from <table_name1> where
(<select count(*) from <table_name2> where <table_name2_colname> = <table_name1>.<colname>)
<标量运算符> <scalar_value>;
----------------------------------------------------------------------------
--例子
set odps.sql.allow.fullscan=true;
select * from shop where
(select count(*) from xxxx_detail where xxxx_detail.xxxx_name = shop.xxxx_name) >= 1;
select_expr:必填。格式为col1_name, col2_name, 正则表达式。
table_name1、table_name2:必填。表的名称。
col_name:必填。表的列名。
标量运算符:必填。例如大于(>)、小于(<)、等于(=)。
scalar_value:必填。标量值
-
交集,并集和补集
1. 交集
--取交集不去重。
<select_statement1> intersect all <select_statement2>;
--取交集并去重。intersect效果等同于intersect distinct。
<select_statement1> intersect [distinct] <select_statement2>;
----------------------------------------------------------------------------
--例子
select * from values (1, 2), (1, 2), (3, 4), (5, 6) t(a, b)
intersect all
select * from values (1, 2), (1, 2), (3, 4), (5, 7) t(a, b);
--结果
+------------+------------+
| a | b |
+------------+------------+
| 1 | 2 |
| 3 | 4 |
+------------+------------+
select_statement1、select_statement2:必填。
distinct:可选。对两个数据集取交集的结果去重。
2. 并集
--取并集不去重。
<select_statement1> union all <select_statement2>;
--取并集并去重。
<select_statement1> union [distinct] <select_statement2>;
----------------------------------------------------------------------------
--例子
select * from values (1, 2), (1, 2), (3, 4) t(a, b)
union all
select * from values (1, 2), (1, 4) t(a, b);
--结果
+------------+------------+
| a | b |
+------------+------------+
| 1 | 2 |
| 1 | 2 |
| 3 | 4 |
| 1 | 2 |
| 1 | 4 |
+------------+------------+
select_statement1、select_statement2:必填。select语句。
distinct:可选。对两个数据集取并集的结果去重。
3. 补集
--取补集不去重。
<select_statement1> except all <select_statement2>;
<select_statement1> minus all <select_statement2>;
--取补集并去重。
<select_statement1> except [distinct] <select_statement2>;
<select_statement1> minus [distinct] <select_statement2>;
----------------------------------------------------------------------------
--例子
select * from values (1, 2), (1, 2), (3, 4), (3, 4), (5, 6), (7, 8) t(a, b)
except all
select * from values (3, 4), (5, 6), (5, 6), (9, 10) t(a, b);
--结果
+------------+------------+
| a | b |
+------------+------------+
| 1 | 2 |
| 1 | 2 |
| 3 | 4 |
| 7 | 8 |
+------------+------------+
select_statement1、select_statement2:必填。select语句。
distinct:可选。对取补集的结果去重。
-
JOIN语句
这里先放一张示意图:
--基本格式
SELECT column1, column2, ...
FROM table1
{left outer|right outer|full outer|inner|natural}
JOIN table2
ON condition;
参数说明:
column1, column2, ...:要选择的字段名称,可以为多个字段。如果不指定字段名称,则会选择所有字段。
table1:要连接的第一个表。
table2:要连接的第二个表。
condition:连接条件,用于指定连接方式。
左连接(left outer join) 可简写为left join |
返回左表中的所有记录,即使右表中没有与之匹配的记录。 |
右连接(right outer join) 可简写为right join |
返回右表中的所有记录,即使左表中没有与之匹配的记录。 |
全连接(full outer join) 可简写为full join |
返回左右表中的所有记录。 |
内连接(inner join) 关键字inner可以省略 |
左右表中至少存在一个匹配行时,inner join返回数据行。 |
自然连接(natural join) |
参与join的两张表根据字段名称自动决定连接字段。 支持outer natural join,支持使用using子句执行join,输出字段中公共字段只出现一次。 |
隐式连接 |
即不指定join关键字执行连接。 |
多路连接 |
多路join连接。支持通过括号指定join的优先级,括号内的join优先级较高。 |
-
半连接和mapjoin
|
MaxCompute支持半连接操作,通过右表过滤左表的数据,使右表的数据不出现在结果集中,可以提高查询性能。 |
2. LEFT SEMI JOIN |
当join条件成立时,返回左表中的数据。如果左表中满足指定条件的某行数据在右表中出现过,则此行保留在结果集中。 |
3. LEFT ANTI JOIN |
当join条件不成立时,返回左表中的数据。如果左表中满足指定条件的某行数据没有在右表中出现过,则此行保留在结果集中。 |
4. MAPJOIN HINT |
当对一个大表和一个或多个小表执行join操作时,可以在select语句中显式指定mapjoin Hint提示以提升查询性能。 |
5. 在select语句中,使用Hint提示/*+ mapjoin(<table_name>) */才会执行mapjoin |
引用小表或子查询时,需要引用别名。 mapjoin支持小表为子查询。 在mapjoin中,可以使用不等值连接或or连接多个条件。您可以通过不写on语句而通过mapjoin on 1 = 1的形式,实现笛卡尔乘积的计算。 mapjoin中多个小表用英文逗号(,)分隔,例如/*+ mapjoin(a,b,c)*/。 |
--允许分区表的全表扫描
SET odps.sql.allow.fullscan=true;
-- 使用mapjoin查询
select /*+ mapjoin(a) */
a.xxxx_name,
a.xxxx_price,
b.xxxx_price
from xxxx_detail_sj a join xxxx_detail b
on a.xxxx_price < b.xxxx_price or a.xxxx_price + b.xxxx_price < 500;
-
SKEWJOIN HINT
其原理图:
--方法1:Hint表名(注意Hint的是表的alias)。
select /*+ skewjoin(a) */ * from T0 a join T1 b on a.c0 = b.c0 and a.c1 = b.c1;
--方法2:Hint表名和认为可能产生倾斜的列,例如表a的c0和c1列存在数据倾斜。
select /*+ skewjoin(a(c0, c1)) */ * from T0 a join T1 b on a.c0 = b.c0 and a.c1 = b.c1 and a.c2 = b.c2;
--方法3:Hint表名和列,并提供发生倾斜的key值。如果是STRING类型,需要加上引号。例如(a.c0=1 and a.c1="2")和(a.c0=3 and a.c1="4")的值都存在数据倾斜。
select /*+ skewjoin(a(c0, c1)((1, "2"), (3, "4"))) */ * from T0 a join T1 b on a.c0 = b.c0 and a.c1 = b.c1 and a.c2 = b.c2;
当两张表Join存在热点,导致出现长尾问题时:
可以通过取出热点key,将数据分为热点数据和非热点数据两部分处理,最后合并的方式,提高Join效率。
-
HAVING子句
--格式
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value
--例子
SELECT Customer,SUM(OrderPrice) FROM Orders
GROUP BY Customer
HAVING SUM(OrderPrice)<2000
MaxCompute SQL的WHERE关键字无法与聚合函数一起使用。
此时可以使用HAVING子句来实现。
表同步
▐ 在线表同步ODPS
这里以MySQL同步ODPS为例子,其他表同步过程也类似。
首先介绍一下步骤:
Step1:进入dataworks,选择:数据开发(DataStudio) ——> 数据集成 ——> Di数据同步 节点:
Step2
:配置来源去向
-
数据来源:数据源选择 “MySQL” ,填入要同步的MySQL的数据表名,会自动搜索到对应的物理表;
-
数据去向:数据源选择“ODPS”,odps的目标表可以先建好,也可以使用“一键生成目标表” 的功能(推荐,简单高效);
-
配置好来源去向后,源头表字段和目标表字段会自动映射匹配;
Step3: 填好调度配置
调度参数,注意参数值不同,展示的时间也不同
注意调度周期,天级,小时级或其他周期
设置好调度依赖,即依赖哪些上级文件的产出,若无可填根节点:
Step4:同步信息填写完成后,在调度配置里配置好调度信息,保存——>发布——>补数据 即可:
接下来,是一些经验总结:
1、“数据来源”的“数据过滤”,不填表示全量同步MySQL的数据;也可以使用类似(gmt_create='${bizdate}')条件来过滤,每次增量同步MySQL的数据 |
2、“数据去向”的“一键生成目标表”功能,建表DDL语句需要人工检查下:
|
3、“数据去向”的“分区信息”,当建的是分区表时,会自动出现该处的分区信息配置;若建的是非分区表,则不必配置 |
4、调度配置中,可以按需选择天、小时或其他时间粒度调度任务 |
5、非该odps项目空间的表不能在该odps项目空间做同步任务 |
6、odps个别字段内容太长,超出mysql表的该字段存储限制,也会导致写入idb失败,报脏数据(修改idb表字段类型,可将对应字段类型修改为 longtext) |
7、idb表字段设为非null,但odps对应字段存在 null值,会导致写入idb失败,报脏数据(修改idb表定义,将对应字段改默认为null) |
8、odps字段和idb字段不必非得一对一保持应,可以手动选择相关字段 连线 ,odps和idb字段可各有未参与同步的字段(注意:idb字段的剩余字段必须是可以自动填充或默认为null类型的) |
▐ ODPS导入Hologres
目前对于需要周期性导入ODPS分区表数据到Hologres, Holo提供了两种导入方式:
方式一:一键可视化导入并且周期性导入,详情见datastudio一键导入
方式二:使用sql导入,详情见hologres sql
-
一键可视化导入
-
新建任务,在数据开发单击一键数据同步,并填写节点信息。
2. 配置信息,填写同步信息。
3. 参数说明
参数 |
配置项 |
说明 |
备注 |
MaxCompute源表选择 |
目标连接 |
Hologres的实例名 |
无 |
目标库 |
Hologres的DB名 |
无 |
|
外部表来源 |
|
|
|
外部表表名字 |
已有的外部表表名 |
外部表用于映射MaxCompute数据,需要与同步数据的MaxCompute表对应 |
|
目标表设置 |
目标Schema |
当前DB下的schema名 |
默认为public,也可以选择新建schema并使用 |
目标表名 |
要导入数据的表名 |
需要同步表数据的内表名称,如已有表,执行后原表和数据将被删除重建 |
|
目标表描述 |
为目标表添加comment |
无 |
|
同步设置 |
同步字段 |
选择需要同步的MaxCompute表字段 |
可以选择全部字段,也可以选择部分字段 |
分区配置 |
选择需要同步的分区字段 |
当前Hologres仅支持一级分区 |
|
索引配置 |
为目标表构建索引 |
索引的创建可以参见文档设置表属性 |
|
SQL Script |
SQL Script |
自动解析出当前运行的SQL,方便参照 |
无 |
-
保持并运行,执行同步任务。任务执行完成之后,可以使用Hologres SQL查看数据。
-
周期性调度
若是您需要周期性导数据,需要单机右侧调度配置进行任务配置,并且保存作业,然后点击右上角发布,将作业发布至生产环境进行周期性调度。
4. 总结
方式一优点:可视化操作,简单快捷,方便小白用户使用,能满足一般场景的使用。
方式一缺点:不支持修改SQL逻辑,若是需要修改,需将SQL Copy再新建一个Hologres SQL节点,根据业务逻辑修改SQL即可。
-
自写sql导入
先介绍一下操作步骤,基本和方式一相同。
-
新建业务流程:选择左侧菜单栏数据开发--新建--业务流程,即可创建一个属于自己的业务流程。
2. 输入业务流程名称
3. 新建Hologres SQL
4. Hologres开发:打开新建的Hologres SQL选择对应Hologres实例,既可使用标准的Postgresql语言开发。
步骤1:准备MaxCompute表数据
--MaxCompute分区表DDL
CREATE TABLE IF NOT EXISTS public_data.dwd_product_movie_basic_info(
movie_name STRING COMMENT '电影名称',
dirctor STRING COMMENT '导演',
scriptwriter STRING COMMENT '编剧',
area STRING COMMENT '制片地区/国家',
actors STRING COMMENT '主演',
`type` STRING COMMENT '类型',
movie_length STRING COMMENT '电影长度',
movie_date STRING COMMENT '上映日期',
movie_language STRING COMMENT '语言',
imdb_url STRING COMMENT 'imdb号'
)
PARTITIONED BY (ds STRING) STORED AS ALIORC;
--查看分区表的某个分区数据
SELECT * FROM public_data.xxxx_movie_basic_info WHERE ds = '20170112';
步骤2
:Hologres新建外部表
移步HoloStudio,在SQL Console中新建一张外部表,用于映射MaxCompute源头表数据。外表的字段顺序和字段类型需要和MaxCompute一一对应。示例使用import foreign schema语法新建外部表SQL如下:
import foreign schema public_data limit to (dwd_product_movie_basic_info)
from server odps_server into public options(if_table_exist 'update');
步骤3
:Holo
gres新建真实存储表
在Hologres中新建一张真实的存储表,用于接收并存储数据。因为本次示例是将MaxCompute分区表导入Hologres分区表,因此需要在Hologres中创建一张分区表。
BEGIN;
CREATE TABLE "public"."holo_dwd_product_movie_basic_info" (
"movie_name" text,
"dirctor" text,
"scriptwriter" text,
"area" text,
"actors" text,
"type" text,
"movie_length" text,
"movie_date" text,
"movie_language" text,
"imdb_url" text,
"ds" text
)
PARTITION BY LIST (ds);
CALL SET_TABLE_PROPERTY('"public"."holo_dwd_product_movie_basic_info"', 'orientation', 'column');
CALL SET_TABLE_PROPERTY('"public"."holo_dwd_product_movie_basic_info"', 'bitmap_columns', '"movie_name","dirctor","scriptwriter","area","actors","type","movie_length","movie_date","movie_language","imdb_url","ds"');
CALL SET_TABLE_PROPERTY('"public"."holo_dwd_product_movie_basic_info"', 'dictionary_encoding_columns', '"movie_name:auto","dirctor:auto","scriptwriter:auto","area:auto","actors:auto","type:auto","movie_length:auto","movie_date:auto","movie_language:auto","imdb_url:auto","ds:auto"');
CALL SET_TABLE_PROPERTY('"public"."holo_dwd_product_movie_basic_info"', 'time_to_live_in_seconds', '3153600000');
comment on column "public"."holo_dwd_product_movie_basic_info"."movie_name" is '电影名称';
comment on column "public"."holo_dwd_product_movie_basic_info"."dirctor" is '导演';
comment on column "public"."holo_dwd_product_movie_basic_info"."scriptwriter" is '编剧';
comment on column "public"."holo_dwd_product_movie_basic_info"."area" is '制片地区/国家';
comment on column "public"."holo_dwd_product_movie_basic_info"."actors" is '主演';
comment on column "public"."holo_dwd_product_movie_basic_info"."type" is '类型';
comment on column "public"."holo_dwd_product_movie_basic_info"."movie_length" is '电影长度';
comment on column "public"."holo_dwd_product_movie_basic_info"."movie_date" is '上映日期';
comment on column "public"."holo_dwd_product_movie_basic_info"."movie_language" is '语言';
comment on column "public"."holo_dwd_product_movie_basic_info"."imdb_url" is 'imdb号';
COMMIT;
步骤4:新建分区子表数据开发
在hologres sql中另开一个作业,用于分区表跑调度。
--创建临时分区子表
BEGIN;
CREATE TABLE IF NOT EXISTS "public".tmp_holo_dwd_product_movie_basic_info_${bizdate} (
"movie_name" text,
"dirctor" text,
"scriptwriter" text,
"area" text,
"actors" text,
"type" text,
"movie_length" text,
"movie_date" text,
"movie_language" text,
"imdb_url" text,
"ds" text
);
COMMIT;
--更新外表数据
import foreign schema public_data limit to (dwd_product_movie_basic_info) from server odps_server into public options(if_table_exist 'update');
--等待30s再导入Hologres,以防Hologres meta信息更新缓存慢导致的数据不一致而同步不成功
select pg_sleep(30);
--将Maxcompute数据导入临时分区子表
INSERT INTO "public".tmp_holo_dwd_product_movie_basic_info_${bizdate}
SELECT
"movie_name",
"dirctor",
"scriptwriter",
"area",
"actors",
"type",
"movie_length",
"movie_date",
"movie_language",
"imdb_url",
"ds"
FROM "public".dwd_product_movie_basic_info
WHERE ds='${bizdate}';
--导入的场景逻辑比较多,下面有两个场景供参考,可以根据业务逻辑二选一即可
--场景1:导入新的分区数据可以参考以下逻辑,
BEGIN;
ALTER TABLE "public".tmp_holo_dwd_product_movie_basic_info_${bizdate} RENAME TO holo_dwd_product_movie_basic_info_${bizdate};
--将临时分区子表绑定在分区父表上
ALTER TABLE "public".holo_dwd_product_movie_basic_info ATTACH PARTITION "public".holo_dwd_product_movie_basic_info_${bizdate} FOR VALUES in ('${bizdate}');
COMMIT;
--场景2:重新对历史分区数据刷新可以参考该逻辑
BEGIN;
ALTER TABLE IF EXISTS "public".holo_dwd_product_movie_basic_info DETACH PARTITION "public".holo_dwd_product_movie_basic_info_${bizdate};
DROP TABLE IF EXISTS "public".holo_dwd_product_movie_basic_info_${bizdate};
ALTER TABLE "public".tmp_holo_dwd_product_movie_basic_info_${bizdate} RENAME TO holo_dwd_product_movie_basic_info_${bizdate};
--将分区子表绑定在分区父表上
ALTER TABLE "public".holo_dwd_product_movie_basic_info ATTACH PARTITION "public".holo_dwd_product_movie_basic_info_${bizdate} FOR VALUES in ('${bizdate}');
COMMIT;
步骤5:调度配置
1)基础属性配置
将基础属性--参数赋值为时间节点,如示例所示:
2)时间属性设置
主要设置时间的重跑属性,其余参数可以根据业务情况自行设置。
3)调度依赖设置
调度依赖为root节点即可(也可以根据业务逻辑选择已有的父节点)请先单击自动解析为是,然后单击使用工作空间根节点,会自动解析出root节点,然后将自动解析设置为否。
步骤6:发布调度
调度参数配置完成之后,单击保存--提交,提交成功后单击运维前往运维中心。
步骤7:运维中心发布
在跳转出来的运维中心,选择已提交成功成功的节点,右键单击节点,选择补数据--当前节点。并根据业务情况设置节点配置。
补完数据之后,在补数据实例可以看到正在运行的任务,以及任务运行状态。
步骤8:Hologres查看数据
任务执行成功之后,将会在Hologres中自动创建对应分区数据的分区子表,可以返回datastudio,新开一个hologres sql节点,执行语句查询数据是否写入成功。
--查看分区子表数据
select * from holo_dwd_product_movie_basic_info_20170112;
--查看分区父表总数据
select count (*) from holo_dwd_product_movie_basic_info;
总结:
方式二优点:可按业务需求进行定制,对sql进行修改,满足复杂特定场景的需求,包括历史数据格式转换、数据清理等;通过SQL导入性能更优。
方式二缺点:有一定学习成本,初学者不太适合,可先通过方式一了解其数据同步的流程和原理,再切换到方式二。
-
流程梳理
-- 1.创建外表
CREATE FOREIGN TABLE IF NOT EXISTS ${odps_table_name} (
"user_id" bigint,
"user_name" text,
"ds" text
)
SERVER odps_server
OPTIONS (project_name 'onetag', table_name '${odps_table_name}');
COMMIT;
-- 2.刷新外表的Schema
IMPORT FOREIGN SCHEMA ${odps_project} LIMIT to
(
${odps_table_name}
)
FROM SERVER odps_server INTO public
OPTIONS(if_table_exist 'update',if_unsupported_type 'error');
-- 3.清理潜在的临时表
BEGIN ;
DROP TABLE IF EXISTS ${holo_table_name}_tmp_${bizhour};
COMMIT ;
-- 4.创建临时表
BEGIN ;
CREATE TABLE IF NOT EXISTS "public".${holo_table_name}_tmp_${bizhour} (
"user_id" bigint,
"user_name" text,
"ds" text,
PRIMARY KEY (user_id,ds)
);
COMMIT;
-- 5.通过查询外表,向临时表插入数据
INSERT INTO ${holo_table_name}_tmp_${bizhour}
SELECT *
FROM public.${odps_table_name}
WHERE ds='${bizhour}';
-- 6.替换子表
BEGIN ;
-- 6.1删除已经存在的子表
DROP TABLE IF EXISTS ${holo_table_name}_${bizhour};
-- 6.2将临时表改名
ALTER TABLE ${holo_table_name}_tmp_${bizhour} RENAME TO ${holo_table_name}_${bizhour};
-- 6.3将临时表绑定至指定分区表
ALTER TABLE ${holo_table_name} ATTACH PARTITION ${holo_table_name}_${bizhour}
FOR VALUES IN ('${bizhour}');
COMMIT ;
-- 7. 大量数据导入后执行ANALYZE分区表父表操作
ANALYZE ${holo_table_name};
注意点:
-
使用临时表的原因是为了保证原子性,只有在导入完成后才绑定至分区表,为了避免导入任务失败时还需要重新删除表等操作。
-
对于更新子表分区数据场景,需要删除子表和重新绑定临时表放入一个事务过程中,保证该过程的事务性。
-
MaxCompute的表数据更新之后,在Hologres存在缓存延迟(一般为10分钟内),建议在导入数据前使用IMPORT FOREIGN SCHEMA语法更新外部表以获取最新数据。
-
导入MaxCompute数据至Hologres时,建议使用SQL导入,不建议使用数据集成导入,因为使用SQL导入性能表现更优。
注意事项
▐ 调度配置
这里强调一下调度参数:
调度参数通常会被用于指代某些动态时间的场景,此场景下,可基于业务日期和定时时间进行调度参数的取值设置。配置调度参数前,您可先了解这两个时间概念,便于后续设置调度参数取值。
取值方式 |
参数格式 |
参数示例 |
相关参考 |
基于业务日期获取时间数据 |
通常,使用大括号${...},结合yyyy、yy、mm及dd自定义组合生成时间参数,获取业务日期前后多少年、月、天。 |
可通过${yyyymmdd}、${yyyy-mm-dd}等${...}自定义时间格式获取,例如:
|
更多赋值示例,请参见自定义参数${...} |
基于定时时间获取时间数据 |
通常,使用中括号$[...],结合yyyy、yy、mm、dd、hh24、mi及ss自定义组合生成时间参数,获取定时时间前后多少年、月、天、小时、分钟、秒。 |
可通过$[yyyymmddhh24miss]等$[...]自定义时间格式获取。例如,取前一天的前一小时,参数表达式为$[yyyymmdd-1-1/24]。 |
|
内置参数:
内置参数 |
定义 |
$bizdate |
业务日期,格式为yyyymmdd,与自定义参数${yyyymmdd}取值一致。 该参数的应用较为广泛,日常调度中默认任务预期运行时间的前一天为业务日期。 |
$cyctime |
任务的定时时间,格式为yyyymmddhh24miss,与自定义参数$[yyyymmddhh24miss]取值一致。 |
$gmtdate |
当前日期,格式为yyyymmdd。 该参数默认取当天日期,执行补数据操作时输入的日期为业务日期+1。 |
$bizmonth |
业务月份,格式为yyyymm。
|
$jobid |
任务所属的业务流程ID。 |
$nodeid |
节点ID。 |
$taskid |
节点产生的实例ID。 |
调度配置的各板块:
配置基础属性 |
名称,节点ID,节点类型,责任人,描述 |
配置调度参数 |
调度参数支持的格式 配置并使用调度参数 |
配置时间属性 |
时间属性配置说明 实例生成方式:发布后即时生成实例 调度周期:分钟/小时/天/月调度 |
配置资源属性 |
默认配置为公共调度资源组。 |
配置调度依赖 |
调度依赖配置 配置同周期调度依赖 配置依赖上一周期(跨周期依赖) 复杂依赖场景调度配置原则 |
配置节点上下文 |
在节点上下文配置本节点输入参数和本节点输出参数 输出参数的取值分为常量和变量两种类型 配置输入参数,在调度依赖中添加依赖的上游节点 |
更多内容请期待下一篇:进阶篇。
¤
拓展阅读
¤
3DXR技术 |
终端技术 |
音视频技术
服务端技术 | 技术质量 | 数据算法
本文分享自微信公众号 - 大淘宝技术(AlibabaMTT)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。