TM1 TI常用场景代码块

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%'));