Indirect variables in TI.
- Steve Rowe
- Site Admin
- Posts: 2455
- Joined: Wed May 14, 2008 4:25 pm
- OLAP Product: TM1
- Version: TM1 v6,v7,v8,v9,v10,v11+PAW
- Excel Version: Nearly all of them
Indirect variables in TI.
I've not see this raised as a technique any where, it would be appear to be a pretty powerful approach to the generalisation of TIs.
For a while now I've been trying to figure out a way of using something like excels Indirect function in TI and today myself and a colleague, Brendan O'Brien, cracked it. Once you figure it out it's a pretty obvious solution but I've never seen it publicised anywhere so I thought I'd post it, given the nature of TM1 though I'm sure someone will be along to say "I've been doing that for years, I thought everyone knew about this"
Anyway so the (simplified) problem is like this.
My TM1 consolidation system has multiple data feeds and I'm not able to influence the structure of the incoming flat files. Each flat file has the columns in a different order.
They all go into the same cube but I don't want to want to have to write and maintain multiple TIs for each of the structurally different flat files.
When I load the file I need to know which field Cost Centre is in so that I can write the data to the cube, but cost centre could be in any of the fields of the incoming file. I want to be able to do this in 1TI without writing a long IF statement, so I could write something like this to solve the issue
If entity='A';
CostCentre=Field3;
ElseIf entity='B';
CostCentre=Field4;
etc for all the many different entites I need to cope with;
EndIf;
Field3 and Field4 etc are the variables names in the TI relating to each column of the incoming file.
This is not generic however, I would need to edit the TI every time a new entity came on line.
What I wanted to do is to be able to populate a file properties cube so that I can say that in the files for entity A cost centre is Field 3 and for entity B the cost centre is in Field 4.
So in my file properties cube I say
.............Cost Centre
Entity A Field3
Entity B Field4
In the TI it's easy for me to retrieve that Field number as a string.
sFieldRef=CellGetS('Datasource_Properties' , 'Entity A' , 'Cost Centre');
So sFieldRef now contains the name of the TI variable that contains the value that I need to use for Cost Centre.
If I write
sCostCentre = sFieldRef;
Then I just make sCostCentre = 'Field3' which is not what I was after.
Reading the help it would seem that the Expand function ought to solve the problem
sCostCentre = Expand('%sFieldRef%');
This still returns sCostCentre = 'Field3' which close reading of the help is the correct behaviour.
Now comes the sneaky bit! If you nest the Expand statements
sCostCentre = Expand ( '%' | Expand ( '%sFieldRef%') | '%');
You get exactly the behaviour we expect, i.e. sCostcentre=Whatever the value that is in the variable Field3.
In some situations where you are trying to build complex and flexible TI processes I expect this to be a powerful technique.
Hopefully I've explained this so it makes sense!
Cheers,
For a while now I've been trying to figure out a way of using something like excels Indirect function in TI and today myself and a colleague, Brendan O'Brien, cracked it. Once you figure it out it's a pretty obvious solution but I've never seen it publicised anywhere so I thought I'd post it, given the nature of TM1 though I'm sure someone will be along to say "I've been doing that for years, I thought everyone knew about this"
Anyway so the (simplified) problem is like this.
My TM1 consolidation system has multiple data feeds and I'm not able to influence the structure of the incoming flat files. Each flat file has the columns in a different order.
They all go into the same cube but I don't want to want to have to write and maintain multiple TIs for each of the structurally different flat files.
When I load the file I need to know which field Cost Centre is in so that I can write the data to the cube, but cost centre could be in any of the fields of the incoming file. I want to be able to do this in 1TI without writing a long IF statement, so I could write something like this to solve the issue
If entity='A';
CostCentre=Field3;
ElseIf entity='B';
CostCentre=Field4;
etc for all the many different entites I need to cope with;
EndIf;
Field3 and Field4 etc are the variables names in the TI relating to each column of the incoming file.
This is not generic however, I would need to edit the TI every time a new entity came on line.
What I wanted to do is to be able to populate a file properties cube so that I can say that in the files for entity A cost centre is Field 3 and for entity B the cost centre is in Field 4.
So in my file properties cube I say
.............Cost Centre
Entity A Field3
Entity B Field4
In the TI it's easy for me to retrieve that Field number as a string.
sFieldRef=CellGetS('Datasource_Properties' , 'Entity A' , 'Cost Centre');
So sFieldRef now contains the name of the TI variable that contains the value that I need to use for Cost Centre.
If I write
sCostCentre = sFieldRef;
Then I just make sCostCentre = 'Field3' which is not what I was after.
Reading the help it would seem that the Expand function ought to solve the problem
sCostCentre = Expand('%sFieldRef%');
This still returns sCostCentre = 'Field3' which close reading of the help is the correct behaviour.
Now comes the sneaky bit! If you nest the Expand statements
sCostCentre = Expand ( '%' | Expand ( '%sFieldRef%') | '%');
You get exactly the behaviour we expect, i.e. sCostcentre=Whatever the value that is in the variable Field3.
In some situations where you are trying to build complex and flexible TI processes I expect this to be a powerful technique.
Hopefully I've explained this so it makes sense!
Cheers,
Technical Director
www.infocat.co.uk
www.infocat.co.uk
- Martin Ryan
- Site Admin
- Posts: 1989
- Joined: Sat May 10, 2008 9:08 am
- OLAP Product: TM1
- Version: 10.1
- Excel Version: 2010
- Location: Wellington, New Zealand
- Contact:
Re: Indirect variables in TI.
We need a "like" button, ala facebook, that's a great idea.
Please do not send technical questions via private message or email. Post them in the forum where you'll probably get a faster reply, and everyone can benefit from the answers.
Jodi Ryan Family Lawyer
Jodi Ryan Family Lawyer
-
- Community Contributor
- Posts: 132
- Joined: Thu Oct 15, 2009 7:45 pm
- OLAP Product: TM1
- Version: 9.4.1 9.5 9.5.1
- Excel Version: 2003 2007
Re: Indirect variables in TI.
Your discovery gave me an idea.
I always hate writing a long string of IF statements when I need to check something in variables in a sequence ( v1, v2, v3, v4, v5, v6, v7, and so on...).
I used your idea to make it simpler.
nNum = 1;
While( nNum <= 7 );
sNum = NumberToString( nNum );
IF( EXPAND( '%v' | EXPAND( '%sNum%' ) | '%' ) @= 'Test' );
....
ENDIF;
nNum = nNum + 1;
END;
Thanks for sharing.
I always hate writing a long string of IF statements when I need to check something in variables in a sequence ( v1, v2, v3, v4, v5, v6, v7, and so on...).
I used your idea to make it simpler.
nNum = 1;
While( nNum <= 7 );
sNum = NumberToString( nNum );
IF( EXPAND( '%v' | EXPAND( '%sNum%' ) | '%' ) @= 'Test' );
....
ENDIF;
nNum = nNum + 1;
END;
Thanks for sharing.
Ankur Jain
-
- Site Admin
- Posts: 1458
- Joined: Wed May 28, 2008 9:09 am
Re: Indirect variables in TI.
@Steve, cast your mind back to the original generic version rollover code for our Newport project. Couldn't this technique be relevant for that kind of task? Suppose you'd still need the cellputn for each dimension count.
- Steve Rowe
- Site Admin
- Posts: 2455
- Joined: Wed May 14, 2008 4:25 pm
- OLAP Product: TM1
- Version: TM1 v6,v7,v8,v9,v10,v11+PAW
- Excel Version: Nearly all of them
Re: Indirect variables in TI.
Ankur,
Yes also a good use of this approach, already used a few times yesterday in the TIs I'm writing.
David, I can't recall that I'm afraid, it was over 5 years ago
I guess the answer would be probably.
Yes also a good use of this approach, already used a few times yesterday in the TIs I'm writing.
David, I can't recall that I'm afraid, it was over 5 years ago

Technical Director
www.infocat.co.uk
www.infocat.co.uk
Re: Indirect variables in TI.
Hi Steve,
we must be patient in our forum.
I have a similar question one year ago.
Unfortunately, I have used the word Activation This Word can still be found in other
Programming languages (APL, PL1 ..).
Within a week I see your solution under 2 topics.
In my case I have a ascii-file with 60 variables. I stored every helpfull Information in a dimension with attributes.
And now i just need a While + your Expand.
Thanks
Brahim
we must be patient in our forum.
I have a similar question one year ago.
Unfortunately, I have used the word Activation This Word can still be found in other
Programming languages (APL, PL1 ..).
Within a week I see your solution under 2 topics.
In my case I have a ascii-file with 60 variables. I stored every helpfull Information in a dimension with attributes.
And now i just need a While + your Expand.
Thanks
Brahim
-
- Community Contributor
- Posts: 147
- Joined: Mon Nov 29, 2010 6:30 pm
- OLAP Product: Cognos TM1
- Version: 10.1
- Excel Version: Office 2010
Re: Indirect variables in TI.
Steve,
Just wanted to add my thanks, you've saved me from pulling out all of my hair.
Just wanted to add my thanks, you've saved me from pulling out all of my hair.
- Steve Rowe
- Site Admin
- Posts: 2455
- Joined: Wed May 14, 2008 4:25 pm
- OLAP Product: TM1
- Version: TM1 v6,v7,v8,v9,v10,v11+PAW
- Excel Version: Nearly all of them
Re: Indirect variables in TI.
I've been meaning to post an update on this.
Ankur posted a use of the nested expand as shown below.
For example to add elements to a dimension in a nice tidy TI sequence.
The help section on Expand appears to have sent many people down a bit a of a blind alley in that it implies that it is only for ODBC statements and so on. It is actually much more powerful even without nesting it.
Cheers,
Ankur posted a use of the nested expand as shown below.
In this example we don't need to nest the expand as we are only trying to get to the value of a variable (not the value of a variable the identifier of which is itself stored in another variable).nNum = 1;
While( nNum <= 7 );
sNum = NumberToString( nNum );
IF( EXPAND( '%v' | EXPAND( '%sNum%' ) | '%' ) @= 'Test' );
....
ENDIF;
nNum = nNum + 1;
END;
For example to add elements to a dimension in a nice tidy TI sequence.
Code: Select all
sElName1='Destination Instance';
sElName2='Destination Cube';
sElName3='Include ruled items';
sElName4='Refresh Dimensions';
sElName5='Rebuild Dimensions';
sElName6='Recreate Cube';
ixDim=1;
sDimName=sDimName17;
While ( ixDim<=5);
sElName=Expand ('%sElName' | numbertostring(ixDim) | '%');
If (Dimix ( sDimName , sElName )=0);
DimensionElementInsert (sDimName , '', sElName , 'S' );
EndIf;
ixDim=ixDim+1;
End;
Cheers,
Technical Director
www.infocat.co.uk
www.infocat.co.uk
-
- Posts: 13
- Joined: Fri Aug 31, 2012 6:30 am
- OLAP Product: TM1
- Version: 10.1
- Excel Version: Excel 2007
Re: Indirect variables in TI.
During your example you checked values in the If clause.
But did you try to assign values like this?
Thanks
CFM04
But did you try to assign values like this?
Code: Select all
ixDim=1;
While ( ixDim<=100);
Expand ('%sElName' | numbertostring(ixDim) | '%') = numbertostring(ixDim);
ixDim=ixDim+1;
End;
CFM04
- Steve Rowe
- Site Admin
- Posts: 2455
- Joined: Wed May 14, 2008 4:25 pm
- OLAP Product: TM1
- Version: TM1 v6,v7,v8,v9,v10,v11+PAW
- Excel Version: Nearly all of them
Re: Indirect variables in TI.
I've never been able to get dynamic variable names to work on the LHS of statements.
Don't forget though that you could build a cube and tear it down on the fly, cubes in this context behave pretty much like an array variable and in a CellPutN you can manipulate the element references pretty much how you like.
http://www.tm1forum.com/viewtopic.php?f=21&t=2691
Cheers,
Don't forget though that you could build a cube and tear it down on the fly, cubes in this context behave pretty much like an array variable and in a CellPutN you can manipulate the element references pretty much how you like.
http://www.tm1forum.com/viewtopic.php?f=21&t=2691
Cheers,
Technical Director
www.infocat.co.uk
www.infocat.co.uk
-
- Posts: 13
- Joined: Fri Aug 31, 2012 6:30 am
- OLAP Product: TM1
- Version: 10.1
- Excel Version: Excel 2007
Re: Indirect variables in TI.
thanks for the hint.
-
- Posts: 1
- Joined: Wed Dec 20, 2017 11:27 pm
- OLAP Product: tm1
- Version: 10.2.2
- Excel Version: 10
Re: Indirect variables in TI.
This works. I really don't understand the Expand statement, but I followed the example and it did exactly what I wanted. I turned two pages of code into about 10 rows.
At the next TM1 Hall of Fame Induction Ceremony this guy should be featured.
At the next TM1 Hall of Fame Induction Ceremony this guy should be featured.
-
- Site Admin
- Posts: 6643
- Joined: Sun May 11, 2008 2:30 am
- OLAP Product: TM1
- Version: PA2.0.9.18 Classic NO PAW!
- Excel Version: 2013 and Office 365
- Location: Sydney, Australia
- Contact:
Re: Indirect variables in TI.
It's Steve, he was inducted years ago.
Expand really isn't very well explained in the manual and IMHO it's not exceptionally well named either. Had I been writing it today I may well have called it something like "Extract" since its function is to extract a value from a variable.
Once you understand that it's relatively easy to use.
(a) A variable is a named "box" in memory which stores a value.
(b) If you know the name of the box in advance, then you have no problem.
(c) The problem arises when you want to figure out the variable name that you need to use based on a loop, or based on other inputs.
(d) For example, suppose that your data source has the variables named vnValue1 to vnValue10, and you don't want to hard code 10 separate lines in your TI to process the values in those 10 variables. Instead you just want to loop from 1 to 10.
(d) It's easy to write a loop which counts from 1 to 10, then just sticks that number on the end of the string 'vnValue' so that on the first loop you get 'vnValue1', on the second loop you get 'vnValue2', on the third one you get 'vnValue3' and so on.
(e) However that just gives you the variable name. To get to what is stored inside that "box", you need a function which takes the variable name, and returns (extracts) what is stored in it. That function is Expand().
You can think of it as drilling into a variable to find out what that variable contains.
"To them, equipment failure is terrifying. To me, it’s 'Tuesday.' "
-----------
Before posting, please check the documentation, the FAQ, the Search function and FOR THE LOVE OF GLUB the Request Guidelines.
-----------
Before posting, please check the documentation, the FAQ, the Search function and FOR THE LOVE OF GLUB the Request Guidelines.
-
- Posts: 4
- Joined: Wed May 24, 2017 8:58 pm
- OLAP Product: TM1
- Version: 10.2.2 looking at PA
- Excel Version: 2016
Re: Indirect variables in TI.
To build a practical example upon Alan's info, I've used this technique to create a dynamic generic process that will find the number of (total or subset) fields in an extract and loop thru them without needing to know the extract name. This is also extremely useful to check for a set of required fields in the extract and send out error notifications.
I needed a way to get the number of fields in a source extract and loop thru those fields. More specifically, we get an accounts property feed containing a number of variables that define a hierarchy structure that we rebuild daily. Our problem is that sometimes this hierarchy structure will change (i.e. the number of these fields will expand/contract) and require code changes. Because we're a larger company and running in a production environment, these changes involve change management, incident tickets and whatnot. My batch file [FieldCount.bat] simply does a regex pattern match on a source extract (using a field name pattern for a subset of fields, or a delimiter pattern to get the total number of fields) and dumps that number out to a text file. My generic TI [UTILITY - GetFieldCount.pro] reads in the text file as a source (one of the few ways I found to pass batch results back to a TI) and passes the number back to the parent TI that executes it using NumericGlobalVariable('DatasourceFieldCount'). So Rather than hard coding a hierarchy structure based uon a set number of fields, my code will dynamically handle the changes.
While they may not be the most succinct pieces of code, they tend to work quite well.
Parent TI PROLOG & METADATA code snippets
This makes use of the two attachments (included as .txt. files):
I needed a way to get the number of fields in a source extract and loop thru those fields. More specifically, we get an accounts property feed containing a number of variables that define a hierarchy structure that we rebuild daily. Our problem is that sometimes this hierarchy structure will change (i.e. the number of these fields will expand/contract) and require code changes. Because we're a larger company and running in a production environment, these changes involve change management, incident tickets and whatnot. My batch file [FieldCount.bat] simply does a regex pattern match on a source extract (using a field name pattern for a subset of fields, or a delimiter pattern to get the total number of fields) and dumps that number out to a text file. My generic TI [UTILITY - GetFieldCount.pro] reads in the text file as a source (one of the few ways I found to pass batch results back to a TI) and passes the number back to the parent TI that executes it using NumericGlobalVariable('DatasourceFieldCount'). So Rather than hard coding a hierarchy structure based uon a set number of fields, my code will dynamically handle the changes.
While they may not be the most succinct pieces of code, they tend to work quite well.
Parent TI PROLOG & METADATA code snippets
This makes use of the two attachments (included as .txt. files):
- FieldCount.bat
- UTILITY - GetFieldCount.pro
Code: Select all
##################
### PROLOG ###
##################
# =================================================================================================== #
# Get a count of the number of field names that match the regular expression pattern
# =================================================================================================== #
# Define a global variable to contain the value (only way to pass info between from a sub-process)
NumericGlobalVariable('DatasourceFieldCount');
# Run the sub process to get the count
ExecuteProcess('UTILITY - GetFieldCount', 'pSource', sSource, 'pPattern', sPattern , 'pFieldCountFile', sFieldCountFile );
##################
### METADATA ###
##################
# =====================================================================================
# Add C-Level consolidation elements to the dimension using the DEPTH#_SYS_NAME field values
# =====================================================================================
# Loop through the possible DEPTH_SYS_NAMEs
idx = 1;
WHILE( idx <= DatasourceFieldCount );
# Build the DataSource field name
sFieldName = 'DEPTH' | NumberToString(idx) | '_SYS_NAME';
# Get the field value in the DataSource INDIRECTLY using the variable containing the field name
sFieldNameValue = TRIM(Expand ('%' | sFieldName | '%'));
# Add consolidation element to the dimension as 'C' level if it does not already exist in the dimension and DEPTH_SYS_NAME value in the DataSource is not blank
IF( DIMIX( pDimName, sChartPrefix | sFieldNameValue) = 0 & LONG(sFieldNameValue) > 0);
DimensionElementInsert( pDimName, '', sChartPrefix | sFieldNameValue, 'C' );
AsciiOutput( sLogFile, 'Added C-Level account: ' | sChartPrefix | sFieldNameValue );
ENDIF;
idx = idx + 1;
End;
- Attachments
-
- FieldCount.bat.txt
- Count regex pattern in file using Windows PowerShell (called by "UTILITY - GetFieldCount.pro")
- (5.15 KiB) Downloaded 1273 times
-
- UTILITY - GetFieldCount.pro.txt
- Field counting utility TI based using regex patterns
- (3.4 KiB) Downloaded 1238 times