Using a feeder based on a condition in TM1 - cognos-tm1

Can an element be fed based on an if condition?
The following is a rule calculation used for evaluating Validation values.
[{'AOP_v1','Forecast_v1'},'Validation', 'Rate'] = N:
IF(ROUNDP(['Phasing Total', 'Rate'] * 100, 5) = 100 % ROUNDP(['Phasing Total', 'Rate'] * 100, 5) = 0, STET, 1);
Is there a way I can feed [{'AOP_v1','Forecast_v1'},'Validation', 'Rate'] with ['Phasing Total', 'Rate'] only when..
ROUNDP(['Phasing Total', 'Rate'] * 100, 5) = 100 % ROUNDP(['Phasing Total', 'Rate'] * 100, 5) = 0
?
Phasing Total
Validation

You can create conditional feeders by using a DB() function on the right hand side of the feeder. Rather than having the cube name hard coded in the DB formula you use an If() function which returns the name of the cube to be fed if the logical condition evaluates to True, or an empty string if it does not:
['FeedFrom']=>DB(IF(YourLogicalTest,'NameOfCube',''), !Dim1, !Dim2, 'Element');
Obviously this is just pseudo-code; the DB function may use various combinations of current element references (the ! operators) and hard coded element names. The key point is, though, that if the If() test returns an empty string then obviously the DB() function does not define anything to be fed.
I would recommend reading this IBM article on rules and feeders in general. This thread on TM1Forum contains some discussion on whether one should or should not use conditional feeders, or find another way.
Another factor that you need to take into account post-dates that thread; in newer versions of TM1 you can use multi-threaded loading to improve the load into memory time. However if you use conditional feeders you have to go back to a single threaded load. This may have a negligible impact on you, or it may be substantial.

Related

How do I select for a row using multiple clauses in PACT smart contract language

The PACT documentation clearly states how to select for a single condition in the where clause, but it is not so clear on how to select for multiple clauses which seems much more general and important for real world use cases than a single clause example.
Pact-lang select row function link
For instance I was trying to select a set of dice throws across the room name and the current round.
(select 'throws (where (and ('room "somename") ('round 2)))
But this guy didn't resolve and the error was not so clear. How do I select across multiple conditions in the select function?
The first thing we tried was to simply select via a single clause which returns a list:
(select 'throws (where (and ('room "somename")))
A: [object{throw-schema},object{throw-schema}]
And then we applied the list operator "filter" to the result:
(filter (= 'with-read-function' 1) (select 'throws (where (and ('room "somename"))))
Please keep in mind we had a further function that read the round and spit back the round number and we filtered for equality of the round value.
This ended up working but it felt very janky.
The second thing we tried was to play around with the and syntax and we eventually found a nice way to express it although not quite so intuitive as we would have liked. It just took a little elbow grease.
The general syntax is:
(select 'throws (and? (where condition1...) (where condition2...))
In this case the and clause was lazy, hence the ? operator. We didn't think that we would have to declare where twice, but its much cleaner than the filter method we first tried.
The third thing we tried via direction from the Kadena team was a function we had yet to purview: Fold DB.
(let* ((qry (lambda (k obj) true)) ;;
(f (lambda(x) [(at 'firstName x), (at 'b x)])) ) (fold-db people (qry) (f)) )
This actually is the most correct answer but it was not obvious from the initial scan and would be near inscrutable for a new user to put together with no pact experience.
We suggest a simple sentence ->
"For multiple conditions use fold-db function."
In the documentation.
This fooled us because we are so used to using SQL syntax that we didn't imagine that there was a nice function like this lying around and we got stuck in our ways trying to figure out conditional logic.

SQL Report Builder: Use aggregate function on ReportItem

I've entered the following expression for a given cell, which is essentially a dollar value divided by a quantity to get a cents per gallon value, labeled as Textbox41:
=ReportItems!Total_Gross_Profit2.Value / ReportItems!Gallon_Qty3.Value
What I was trying to do is use this expression for an AVG aggregation in another cell =avg(ReportItems!Textbox41.Value), but I'm getting an error:
The Value expression for the textrun
'Textbox79.Paragraphs[0].TextRuns[0]' uses an aggregate function on a
report item. Aggregate functions can be used only on report items
contained in page headers and footers.
Is there some limitation that does not allow aggregations on ReportItems? I've also tried the following, which also did not work:
=AVG(ReportItems!Total_Gross_Profit2.Value / ReportItems!Gallon_Qty3.Value)
Where am I going wrong here?
Regarding your question:
Is there some limitation that does not allow aggregations on ReportItems?
You have your answer in the error message you provided.
As for the resolution, it's hard to give precise guidance with the information you provided, but in general, start thinking in terms of dataset fields instead of report objects. If you're operating from inside a matrix or table, and if the values for 'Total_Gross_Profit' and 'Gallon_Qty_3' look something analogous to this:
= ReportItems!ProfitsFromX.Value + ReportItems!ProfitsFromY.Value
= ReportItems!GallonQtyA.Value + ReportItems!GallonQtyB.Value
Point to the fields directly instead:
= Fields!ProfitsFromX.Value + Fields!ProfitsFromY.Value
= Fields!GallonQtyA.Value + Fields!GallonQtyB.Value
That way, when it comes to aggregation, it's more clear what to do:
= avg(
(Fields!ProfitsFromX.Value + Fields!ProfitsFromY.Value)
/ (Fields!GallonQtyA.Value + Fields!GallonQtyB.Value)
)
And if you find that cumbersome, you can create calculated fields on the dataset object, and reference those instead where appropriate.

SSRS The textrun uses a First aggregate in an outer aggregate (Different datasets)

Ok, I'm working on a multi-data report that merges data from many servers.
dataset1 = One of six datasets with the data I need.
ds_BusinessDays = A calendar table dataset with Specific dates and numbers that change every day/week/month.
I'm trying to use a SWITCH where MonthName(Date) from dataset1 = MonthName(Date2) from ds_BusinessDays. Then Sum the total count.
I have successfully used similar cross dataset calculations like
SUM(SWITCH when Data = "Product" then 1) / SUM(businessdaysinmonth, "ds_BusinessDays")
This was to get the Average. works like a charm.
=SUM(
SWITCH(Fields!Requested_Month.Value = MonthName(Month(First(Fields!PreviousBusinessDate.Value, "ds_BusinessDays")))
,1)
)
All Fields in ds_BusinessDays dataset are 1 entry results. Example, "PreviousBusinessDay" = "6/21/2019". So I want my code to do something like this.
When MonthName(Date) form dataset1 = MonthName(PreviousBusinessDate) from ds_BusinessDays then 1. Sum all of that up to get my a total for that month.
The problem is that FIRST and SUM are the only fields available to me when using fields from another dataset. They can't be used in an Aggregate within an Aggregate.
Is there a substitute that I can use for First in First(Fields!PreviousBusinessDate.Value, "ds_BusinessDays")?
Why are you using a SWITCH when you only have a single conditional? I think an IIF would be much easier to read. Also, if ds_BusinessDays.PreviousBusinessDate is a single entry, why do you even need FIRST? There should only be one result. If you're trying to do what I think you're trying to do, this expression should do it.
= SUM(IIF(Fields!Requested_Month.Value = MonthName(Month(Fields!PreviousBusinessDate.Value, "ds_BusinessDays")), 1, 0))
To add additional detail, a SWITCH is best used for more than 2 conditional statements. If you're only trying to compare two fields, you can just use a simple IIF. An example of when SWITCH is necessary:
=SUM(SWITCH(Fields!Date.Value = Fields!Today.Value, 1,
Fields!Date.Value = Fields!Yesterday.Value, 2,
Fields!Date.Value = Fields!Tomorrow.Value, 3,
true, 0))
This expression would check Date against three different fields and return a different count for each, ending with an always true condition that catches everything else. Your expression doesn't need a SWITCH.

Power Query M loop table / lookup via a self-join

First of all I'm new to power query, so I'm taking the first steps. But I need to try to deliver sometime at work so I can gain some breathing time to learn.
I have the following table (example):
Orig_Item Alt_Item
5.7 5.10
79.19 79.60
79.60 79.86
10.10
And I need to create a column that will loop the table and display the final Alt_Item. So the result would be the following:
Orig_Item Alt_Item Final_Item
5.7 5.10 5.10
79.19 79.60 79.86
79.60 79.86 79.86
10.10
Many thanks
Actually, this is far too complicated for a first Power Query experience.
If that's what you've got to do, then so be it, but you should be aware that you are starting with a quite difficult task.
Small detail: I would expect the last Final_Item to be 10.10. According to the example, the Final_Item will be null if Alt_Item is null. If that is not correct, well that would be a nice first step for you to adjust the code below accordingly.
You can create a new blank query, copy and paste this code in the Advanced Editor (replacing the default code) and adjust the Source to your table name.
let
Source = Table.Buffer(Table1),
AddedFinal_Item =
Table.AddColumn(
Source,
"Final_Item",
each if [Alt_Item] = null
then null
else List.Last(
List.Generate(
() => [Final_Item = [Alt_Item], Continue = true],
each [Continue],
each [Final_Item =
Table.First(
Table.SelectRows(
Source,
(x) => x[Orig_Item] = [Final_Item]),
[Alt_Item = "not found"]
)[Alt_Item],
Continue = Final_Item <> "not found"],
each [Final_Item])))
in
AddedFinal_Item
This code uses function List.Generate to perform the looping.
For performance reasons, the table should always be buffered in memory (Table.Buffer), before invoking List.Generate.
List.Generate is one of the most complex Power Query functions.
It requires 4 arguments, each of which is a function in itself.
In this case the first argument starts with () and the other 3 with each (it should be clear from the outline above: they are aligned).
Argument 1 defines the initial values: a record with fields Final_Item and Continue.
Argument 2 is the condition to continue: if an item is found.
Argument 3 is the actual transformation in each iteration: the Source table is searched (with Table.SelectRows) for an Orig_Item equal to Alt_Item. This is wrapped in Table.First, which returns the first record (if any found) and accepts a default value if nothing found, in this case a record with field Alt_Item with value "not found", From this result the value of record field [Alt_Item] is returned, which is either the value of the first record, or "not found" from the default value.
If the value is "not found", then Continue becomes false and the iterations will stop.
Argument 4 is the value that will be returned: Final_Item.
List.Generate returns a list of all values from each iteration. Only the last value is required, so List.Generate is wrapped in List.Last.
Final remark: actual looping is rarely required in Power Query and I think it should be avoided as much as possible. In this case, however, it is a feasible solution as you don't know in advance how many Alt_Items will be encountered.
An alternative for List.Generate is using a resursive function.
Also List.Accumulate is close to looping, but that has a fixed number of iterations.
This can be solved simply with a self-join, the open question is how many layers of indirection you'll be expected to support.
Assuming just one level of indirection, no duplicates on Orig_Item, the solution is:
let
Source = #"Input Table",
SelfJoin1 = Table.NestedJoin( Source, {"Alt_Item"}, Source, {"Orig_Item"}, "_tmp_" ),
Expand1 = ExpandTableColumn( SelfJoin1, "_tmp_", {"Alt_Item"}, {"_lkp_"} ),
ChkJoin1 = Table.AddColumn( Expand1, "Final_Item", each (if [_lkp_] = null then [Alt_Item] else [_lkp_]), type number)
in
ChkJoin1
This is doable with the regular UI, using Merge Queries, then Expand Column and adding a custom column.
If yo want to support more than one level of indirection, turn it into a function to be called X times. For data-driven levels of indirection, you wrap the calls in a list.generate that drop the intermediate tables in a structured column, though that's a much more advanced level of PQ.

Reduced Survey Frequency - Salesforce Workflow

Hoping you can help me review the logic below for errors. I am looking to create a workflow that will send a survey out to end users on a reduced frequency. Basically, it will check the Account object of the Case for a field, 'Reduced Survey Frequency', which contains a # and will not send a survey until that # of days has passed since the last date set on the Contact field 'Last Survey Date'. Please review the code and let me know any recommended changes!
AND( OR(ISPICKVAL(Status,"Closed"), ISPICKVAL(Status,"PM Sent")),
OR(CONTAINS(RecordType.Name,"Portal Case"),CONTAINS(RecordType.Name,"Standard Case"),
CONTAINS(RecordType.Name,"Portal Closed"),
CONTAINS(RecordType.Name,"Standard Closed")),
NOT( Don_t_sent_survey__c )
,
OR(((TODAY()- Contact.Last_Survey_Date__c) >= Account.Reduced_Survey_Frequency__c ),Account.Reduced_Survey_Frequency__c==0,
ISBLANK(Account.Reduced_Survey_Frequency__c),
ISBLANK(Contact.Last_Survey_Date__c)
))
Thanks,
Brian H.
Personally I prefer the syntax where && and || are used instead of AND(), OR()functions. It just reads bit nicer to me, no need to trace so many commas, keep track of indentation in the more complex logic... But if you're more used to this Excel-like flow - go for it. In the end it has to be readable for YOU.
Also I'd consider reordering this a bit - simple checks, most likely to fail first.
The first part - irrelevant to your question
Don't use RecordType.Name because these Names can be translated to say French and it will screw your logic up for users who will select non-English as their preferred language. Use RecordType.DeveloperName, it's safer.
CONTAINS - do you really have so many record types that share this part in their name? What's wrong with normal = comparison? You could check if the formula would be more readable with CASE() statement. Or maybe flip the logic if there are say 6 rec types and you've explicitly listed 4 (this might have to be reviewed though when you add new rec. type). If you find yourself copy-pasting this block of 4 checks frequently - consider making a helper formula field with it...
The second part
ISBLANK checks could be skipped if you'll properly use the "treat nulls as blanks / as zeroes" setting at the bottom of formula editor. Because you're making check like
OR(...,
Account.Reduced_Survey_Frequency__c==0,
ISBLANK(Account.Reduced_Survey_Frequency__c),
...
)
which is essentially what this thing was designed for. I'd flip it to "treat nulls as zeroes" (but that means the ISBLANK check will never "fire"). If you're not comfortable with that - you can also "safely compare or substract" by using
BLANKVALUE(Account.Reduced_Survey_Frequency__c,0)
Which will have the similar "treat null as zero" effect but only in this one place.
So... I'd end up with something like this:
(ISPICKVAL(Status,'Closed') || ISPICKVAL(Status, 'PM Sent')) &&
(RecordType.DeveloperName = 'Portal_Case' ||
RecordType.DeveloperName = 'Standard_Case' ||
RecordType.DeveloperName = 'Portal_Closed' ||
RecordType.DeveloperName = 'Standard_Closed'
) &&
NOT(Don_t_sent_survey__c) &&
(Contact.Last_Survey_Date__c + Account.Reduced_Survey_Frequency__c < TODAY())
No promises though ;)
You can easily test them by enabling debug logs. You'll see there the workflow formula together with values that are used to evaluate it.
Another option is to make a temporary formula field with same logic and observe (in a report?) where it goes true/false for mass spot check.

Resources