TM1 TI进程常用场景代码块总结。
0 常用规范
0.0 代码规范
- 习惯写注释 #
- 参数命名有实际含义,避免a,b这种无意义命名
- 变量命名有实际含义,避免a,b这种无意义命名
- if, elseif, else, while 等语句中的代码块 ,一定要缩进!!! (两个空格或四个空格,看个人或项目风格)
0.1 前序开头注释模块(参考)
############################################################################
#@作者:
#@时间:2020-09-15
#@功能描述:
# a.
# b.
# c.
#@参数:
# null
#@开发步骤:
# 1、
# 2、
cProcessStartTimeNum=now;
cProcessStartTime=Timst(now,'\Y-\m-\d \h:\i:\s');
############################################################################
0.2 结语记录TI执行记录(参考,且这里的cube需要提前预置)
################################# 结语 ###########################################
#打印Porcess执行日志
cProcessname=GetProcessname();
cProcessExeUser=TM1User();
cProcessEndTimeNum=now;
cProcessEndTime=Timst(now,'\Y-\m-\d \h:\i:\s');
cProcessHowLongNum=(cProcessEndTimeNum-cProcessStartTimeNum)*24*3600;
#5选1:1-前台表单;2-后台进程;3-JAVA程序;4-SHELL脚本;5-其他进程
cProcessExeType=2;
cProcessParam='Null';
RunProcess('_TI_Sys_ProcessExeLog',
'cProcessname',cProcessname,
'cProcessStartTime',cProcessStartTime,
'cProcessEndTime',cProcessEndTime,
'cProcessExeUser',cProcessExeUser,
'cProcessExeType',cProcessExeType,
'cProcessHowLongNum',cProcessHowLongNum,
'cProcessParam',cProcessParam);
################################# 结语 ###########################################
1 常用场景
1.1 ti日志操作记录
此cube可用于记录ti执行记录,可设置最大条数,每次ti执行时调用 0.2 处的代码即可记录。
1.1.2 创建cube的TI:
入参:PMaxLogCount 保留最近多少条记录 ; PIsForceCreate 是否强制创建 1/0
前序:
############################################################################
#@作者:
#@功能描述:
# a. 创建cube,用于记录TI执行log信息 ;
# b. 包括起始时间 、结束时间、用户、运行方式、 一共耗时、 输入参数
# c. 其他的后续迭代
#@参数:
# PMaxLogCount-保留最近多少条记录;
# PIsForceCreate-是否强制创建 1/0
#@开发步骤:
# 1、初始变量,其中PMaxLogCount默认100
# 2、如果已经存在cube,且PIsForceCreate=0不强制创建 就跳过
# 3、否则 如果已经存在cube,且PIsForceCreate=1强制创建,先删除存在的cube和维度
# 创建cube : 先创建维度_Sys_ProcessMaxLogCount,并根据PMaxLogCount初始化维度元素
# 创建维度_Sys_ProcessLogInfo,并初始化维度元素
# 创建cube
############################################################################
#PMaxLogCount默认100
if(PMaxLogCount = 0);
PMaxLogCount=100;
endif;
CubeName='_Sys_ProcessExeLog';
CubeIsExist=CubeExists(CubeName);
SeverityLevelInfo='INFO';
DimName1='}Processes';
DimName2='_Sys_ProcessMaxLogCount';
DimName2Root='ProcessMaxLogCount';
DimName3='_Sys_ProcessLogInfo';
If(CubeIsExist = 1 & PIsForceCreate = 0);
LogOutput(SeverityLevelInfo, 'Cube'|CubeName|'已经创建,不必多次创建!');
Else;
if(CubeIsExist = 1 & PIsForceCreate <> 0);
LogOutput(SeverityLevelInfo, 'Cube'|CubeName|'已经创建,重新创建中...');
CubeDestroy(CubeName);
DimensionDestroy(DimName2);
DimensionDestroy(DimName3);
endif;
LogOutput(SeverityLevelInfo, '开始创建LOGCube:'|CubeName|'。其中参数最大记录数为'|NumberToString(PMaxLogCount));
LogOutput(SeverityLevelInfo, '开始创建Log最大记录数维度:'|DimName2|'。其中最大记录数为'|NumberToString(PMaxLogCount));
if(DimensionExists(DimName2) = 1);
DimensionDestroy(DimName2);
endif;
DimensionCreate(DimName2);
DimensionElementInsertDirect(DimName2,'' , DimName2Root,'N');
i=1;
n=PMaxLogCount;
while( i <= n);
DimensionElementComponentAddDirect(DimName2, DimName2Root,'最近'|NumberToString(i)|'次', 1);
i=i+1;
end;
LogOutput(SeverityLevelInfo, '开始创建进程信息维度:'|DimName3);
if(DimensionExists(DimName3) = 1);
DimensionDestroy(DimName3);
endif;
DimensionCreate(DimName3);
DimensionElementInsertDirect(DimName3, '', '起始时间','S');
DimensionElementInsertDirect(DimName3, '', '结束时间','S');
DimensionElementInsertDirect(DimName3, '', '用户','S');
DimensionElementInsertDirect(DimName3, '', '运行方式','S');
DimensionElementInsertDirect(DimName3, '', '耗时','S');
DimensionElementInsertDirect(DimName3, '', '进程输入参数','S');
DimensionElementInsertDirect(DimName3, '', '进程记录总条数','N');
CubeCreate(CubeName, DimName1, DimName2,DimName3);
LogOutput(SeverityLevelInfo, '创建成功!');
Endif;
1.1.3 调用记录日志的TI:
TI名:_TI_Sys_ProcessExeLog
入参:
- cProcessname 进程名
- cProcessStartTime 进程开始时间
- cProcessEndTime 进程结束时间
- cProcessExeUser 进程执行者
- cProcessExeType 进程执行方式 #5选1:1-前台表单;2-后台进程;3-JAVA程序;4-SHELL脚本;5-其他进程
- cProcessHowLongNum 耗时
- cProcessParam 进程参数值
前序:
############################################################################
#@作者:
#@功能描述:
# a. 记录TI执行日志
# b.
# c.
#@参数:
# cProcessname,cProcessStartTime,cProcessEndTime,cProcessExeUser,cProcessExeType,cProcessHowLongNum,cProcessParam
#@开发步骤:
# 1、初始变量
# 2、根据当前记录的总条数,将之前的日志信息进行偏移 第n次放在n+1次上,n-1次放在n-2次...第1次放在第2次
# 3、最终将最新信息放在第1次
############################################################################
# 1、初始变量
cSys_ProcessExeLog='_Sys_ProcessExeLog';
cProcessLogCountNow=CellGetN(cSys_ProcessExeLog,cProcessname,'最近1次','进程记录总条数');
cProcessLogCount=cProcessLogCountNow;
cProcessLogCountMax=ElCompn('_Sys_ProcessMaxLogCount','ProcessMaxLogCount');
# 2、根据当前记录的总条数,将之前的日志信息进行偏移 第n次放在n+1次上,n-1次放在n-2次...第1次放在第2次
if(cProcessLogCount >= cProcessLogCountMax);
cProcessLogCount = cProcessLogCountMax - 1;
endif;
if(cProcessLogCount >0 );
while(cProcessLogCount>0);
cProcessLogCountNext=cProcessLogCount+1;
cValueStartTime=CellGetS(cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount)|'次','起始时间');
cValueEndTime=CellGetS(cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount)|'次','结束时间');
cValueExeUser=CellGetS(cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount)|'次','用户');
cValueExeType=CellGetS(cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount)|'次','运行方式');
cValueHowLong=CellGetS(cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount)|'次','耗时');
cValueProcessParam=CellGetS(cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount)|'次','进程输入参数');
CellPutS(cValueStartTime,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount+1)|'次','起始时间');
CellPutS(cValueEndTime,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount+1)|'次','结束时间');
CellPutS(cValueExeUser,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount+1)|'次','用户');
CellPutS(cValueExeType,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount+1)|'次','运行方式');
CellPutS(cValueHowLong,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount+1)|'次','耗时');
CellPutS(cValueProcessParam,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cProcessLogCount+1)|'次','进程输入参数');
cProcessLogCount=cProcessLogCount-1;
end;
endif;
# 3、最终将最新信息放在第1次
cLastTimeCount=1;
CellPutS(cProcessStartTime,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cLastTimeCount)|'次','起始时间');
CellPutS(cProcessEndTime,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cLastTimeCount)|'次','结束时间');
CellPutS(cProcessExeUser,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cLastTimeCount)|'次','用户');
#cProcessExeType 5选1:1-前台表单;2-后台进程;3-JAVA程序;4-SHELL脚本;5-其他进程
if(cProcessExeType=1);
cProcessExeTypeStr='1-前台表单';
elseif(cProcessExeType=2);
cProcessExeTypeStr='2-后台进程';
elseif(cProcessExeType=3);
cProcessExeTypeStr='3-JAVA程序';
elseif(cProcessExeType=4);
cProcessExeTypeStr='4-SHELL脚本';
elseif(cProcessExeType=5);
cProcessExeTypeStr='5-其他进程';
else;
cProcessExeTypeStr='2-后台进程';
endif;
CellPutS(cProcessExeTypeStr,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cLastTimeCount)|'次','运行方式');
CellPutS(NumberToString(cProcessHowLongNum)|'s',cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cLastTimeCount)|'次','耗时');
CellPutS(cProcessParam,cSys_ProcessExeLog,cProcessname,'最近'|NumberToString(cLastTimeCount)|'次','进程输入参数');
CellPutN(cProcessLogCountNow+1,cSys_ProcessExeLog,cProcessname,'最近1次','进程记录总条数');
logoutput('INFO','##### 进程'|cProcessname|'执行日志记录 #####');
logoutput('INFO','进程:'|cProcessname|' 起始时间:'|cProcessStartTime);
logoutput('INFO','进程:'|cProcessname|' 执行用户:'|cProcessExeUser);
logoutput('INFO','进程:'|cProcessname|' 运行方式:'|cProcessExeTypeStr);
logoutput('INFO','进程:'|cProcessname|' 一共耗时:'|NumberToString(cProcessHowLongNum)|'s');
logoutput('INFO','进程:'|cProcessname|' 输入参数:'|cProcessParam);
logoutput('INFO','进程:'|cProcessname|' 结束时间:'|cProcessEndTime);
1.2 数据备份
执行bat/sh脚本完成数据备份。bat内容根据情况编写。
Savedataall;
filename='D:\backup\backup_tm1.bat';
ExecuteCommand(filename,1);
1.3 动态创建子集并遍历所有元素
子集名需要加时间戳和rand保证唯一;
先创建子集然后SubsetMDXSet 设置表达式,而不是用SubsetCreatebyMDX直接创建,因为如果动态表达式的结果没有元素的话 SubsetCreatebyMDX会失败;
dimName='维度';
subsetName=getprocessname()|参数1|参数2|Timst(now,'\Y\m\d\h\i\s')|numbertostring(rand);
MDX_Expression='动态子集表达式';
SubsetDestroy(dimName, subsetName);
SubsetCreate(dimName, subsetName);
SubsetMDXSet(dimName,subsetName, MDX_Expression);
i=1;
n=SubsetGetSize(dimName,subsetName);
while(i<=n);
eleName=SubsetGetElementName(dimName,subsetName, i);
# 事务处理
i=i+1;
end;
SubsetDestroy(dimName, subsetName);
1.4 循环list(list是由逗号,分隔的多个字符串)
假设一个TI ,入参是一个list,list是由逗号,分隔的多个字符串,ti解析list代码块如下:
arrayList='字符串1,字符串2,字符串3';
arrayListNew=arrayList;
arrayListNewLong=long(arrayListNew);
arrayListNewCommaIndex=scan(',',arrayListNew);
while(arrayListNewLong>0);
# 最后一个字符串特殊情况
if(arrayListNewCommaIndex=0);
array=arrayListNew;
arrayListNew='';
arrayListNewLong=0;
# 除了最后一个字符串之外的情况
else;
array=subst(arrayListNew,1,arrayListNewCommaIndex-1);
arrayListNew=subst(arrayListNew,arrayListNewCommaIndex+1,arrayListNewLong-arrayListNewCommaIndex);
arrayListNew=trim(arrayListNew);
arrayListNewLong=long(arrayListNew);
arrayListNewCommaIndex=scan(',',arrayListNew);
endif;
# array 就是分隔之后的字符串,此后可进行事务处理
logoutput('INFO',expand('#### test #### 分隔后的字符串是:%array%'));
end;
1.5 替换字符串中的某个字符
有时给TI传过来的参数值,可能包含了特殊字符,因此在使用之前需要替换。常见的特殊字符有 \/:*?"<>|}
# 替换字符 打印新的字符串 \/:*?"<>|}
# 比如将 strOld 中的 \ 替换为 _
strOld='a\\\b\\/c:d*e?f"g<h>i}';
specialSymbols='\';
specialSymbolsNew='_';
positionOfSpecialSymbolsInStr=scan(specialSymbols,strOld);
longOfStr=long(strOld);
logoutput('INFO',expand('替换前:%strOld%'));
while(positionOfSpecialSymbolsInStr>0);
strOld=subst(strOld,1,positionOfSpecialSymbolsInStr-1)|specialSymbolsNew|subst(strOld,positionOfSpecialSymbolsInStr+1,longOfStr-positionOfSpecialSymbolsInStr);
positionOfSpecialSymbolsInStr=scan(specialSymbols,strOld);
longOfStr=long(strOld);
logoutput('INFO',expand('替换后:%strOld%'));
end;
1.6 批量给cube创建单元格权限
默认开所有维度。创建一个通用ti,提供cube名,即可创建单元格权限。
#### cube创建单元格权限
cube_security_pre = '}CellSecurity_';
cubename_security = cube_security_pre|cubeName;
if(CubeExists(cubename_security)=0);
cubeDimCount=CubeDimensionCountGet(cubeName);
i=1;
n=cubeDimCount;
expression='';
while(i<=n);
if(i=1);
expression='1';
else;
expression=expression|':1';
endif;
i=i+1;
end;
logoutput('WARN',expand('###### 【%cubeName%】有【%cubeDimCount%】个维度:创建cube单元格权限【%expression%】。'));
CellSecurityCubeCreate(cubeName, expression);
endif;
1.7 动态创建视图做数据源(数据拷贝常用)
比如根据项目、版本维度创建动态视图做数据源:
cubeName='cube名';
viewNameSource=getprocessname()|维度元素参数1|维度元素项目参数2数|'_Source'|Timst(now,'\Y\m\d\h\i\s')|numbertostring(rand);
subsetNameSource=viewNameSource;
## 清视图
viewdestroy(cubeName,viewNameSource);
viewcreate(cubeName,viewNameSource);
## 初始化子集
dimName1='维度1';
subsetdestroy(dimName1,subsetNameSource);
subsetcreate(dimName1,subsetNameSource);
SubsetElementInsert(dimName1,subsetNameSource,维度参数1,1);
ViewSubsetAssign(cubeName,viewNameSource,dimName1,subsetNameSource);
dimName2='维度2';
MDX_Expression_Source='{DESCENDANTS(['|dimName2|'].['|维度参数2|'])}';
subsetdestroy(dimName2,subsetNameSource);
SubsetCreatebyMDX(subsetNameSource,MDX_Expression_Source);
ViewSubsetAssign(cubeName,viewNameSource,dimName2,subsetNameSource);
## 设置源视图不跳过父项、跳过规则、跳过0值
ViewExtractSkipCalcsSet(cubeName,viewNameSource,0);
ViewExtractSkipRuleValuesSet(cubeName,viewNameSource,1);
ViewExtractSkipZeroesSet(cubeName,viewNameSource,1);
## 指定源视图
datasourcetype='VIEW';
datasourcenameforserver=cubeName;
datasourcecubeview=viewNameSource;
1.8 关系库sql做数据源
# 指定数据源
DataSourceType='ODBC';
# 因为线上环境和uat的值不同, 其中 odbc名,odbc账号,odbc密码尽量存储到tm1中
DatasourceNameForServer=attrs('_Sys_Config','odbcName','系统参数值');
DatasourceUserName=attrs('_Sys_Config','odbcUser','系统参数值');
DatasourcePassword=attrs('_Sys_Config','odbcPassword','系统参数值');
DatasourceQuery=
'select
字段1,字段2,字段3...
from table t1
where t1.project_code='''|pProjectCode|''' '
;
1.9 导出数据到关系库 执行sql等
# 因为线上环境和uat的值不同, 其中 odbc名,odbc账号,odbc密码尽量存储到tm1中
# 0.设置odbc信息
odbcName=attrs('_Sys_Config','odbcName','系统参数值');
odbcUser=attrs('_Sys_Config','odbcUser','系统参数值');
odbcPassword=attrs('_Sys_Config','odbcPassword','系统参数值');
odbcopenex(odbcName,odbcUser,odbcPassword,1);
# 执行sql
sql_update='sql语句可拼接';
# 常见的拼接 : '''|字符串类型变量或参数|''' , ''字符串值''
ODBCOUTPUT(odbcName,sql_update);
ODBCClose(odbcName);
1.10 日期时间格式转换
# 获取当前时间 yyyymmddhhmiss
currtime=Timst(now,'\Y\m\d\h\i\s');
logoutput('INFO',expand('#### 当前时间:%currtime%'));
# 字符串日期转数字:2022-06-17 转为tm1日期数字格式 22813
time_str='2022-06-17';
time_num=dayno(time_str);
logoutput('INFO',expand('#### 时间%time_str%转换后的结果:%time_num%'));
# 数字日期转字符串:excel录入的数字日期 44444,转换为yyyy-mm-dd格式 2021-09-05
time_num=44444;
time_str=date(time_num-21916,1);
logoutput('INFO',expand('#### 时间%time_num%转换后的结果:%time_str%'));
# 两个日期相差天数
time1_str='2022-02-03';
time2_str='2022-03-03';
time1_num=dayno(time1_str);
time2_num=dayno(time2_str);
time_diff=time2_num-time1_num;
logoutput('INFO',expand('#### %time2_str%减去%time1_str%有%time_diff%天。'));
# 根据日期yyyymmdd,获取该月份实际有多少天,常用于分摊等
# 获取当月1号,转为数字;获取下个月1号 转为数字;两个相减的结果即为当月的天数
time_str='2022-06-17';
time_curr_year=subst(time_str,1,4);
time_curr_month=subst(time_str,6,2);
time_next_year=time_curr_year;
time_next_month_num=stringtonumber(time_curr_month)+1;
time_next_month=numbertostring(time_next_month_num);
# time_next_month补位
if(time_next_month_num<10);
time_next_month='0'|numbertostring(time_next_month_num);
endif;
# 如果当月是12月,下个月是次年的1月
if(time_curr_month@='12');
time_next_year=numbertostring(stringtonumber(time_curr_year)+1);
time_next_month='01';
endif;
time_curr_month_firstday=time_curr_year|'-'|time_curr_month|'-01';
time_next_month_firstday=time_next_year|'-'|time_next_month|'-01';
# 当月天数=次月首日day-当月首日day得到的数字
time_month_days=dayno(time_next_month_firstday)-dayno(time_curr_month_firstday);
logoutput('INFO',expand('#### 日期%time_str%的当月首日是:%time_curr_month_firstday%,次月首日是:%time_next_month_firstday%,当月实际天数是:%time_month_days%'));