SSRS Variable Expression - Sum, Sum, Scope? - tsql

I'm trying to write an expression for a variable (not parameter), so that I can use/reference it to do a calculation in another textbox. I have multiple datasets, and I need the SUM(SUM(Fields!amount.Value)) for each of these datasets. I am then going to use these numbers in another textbox, adding them with each other. I need some assistance with the syntax. I am able to use SUM by itself, without an issue. For example, this works fine:
=SUM(Fields!Amount.Value, "DataSet1")
But I get an error when trying to amend it to the following (which is what I actually need):
=SUM(SUM(Fields!amt.Value, "Acctrange_90300_90399_InterestExpenses"))
I get an error saying
"The variable expression for the report 'body' uses an aggregate
expression without a scope. A scope is required for all aggregates
used outside of a data region unless the report contains exactly one dataset."
I have a hunch that there's a problem with my syntax/parantheses placement. Any suggestions?

could you please provide a detailed example with maybe sample data and an expected solution?
Because I do not understand why you want to SUM(SUM()). The inner SUM() would result in a single integer value, why would you want to do another SUM on just a single value. even if it worked, it would just be the same value. I apologize if I understood the question wrongly, i can't comment, so i am answering, but I want to know clearly what you are looking for. I can understand if you are trying to do SUM( SUM(), SUM(), SUM()...). As in, sum of sums.
Sorry again for answering just to inquire more info, but I can't see a comment option.
UPDATE:
ok now i think you have something like
| a | b | c | d |
---------------------------
1 | * | * | * | * |
---------------------------
2 | * | * | * | * |
---------------------------
3 | * | * | * | * |
---------------------------
total | w | x | y | z |
so SUM(Fields!a.Value) would give you w, and SUM(Fields!b.Value) would give you x, and so on.
and you want w+x+y+z? If that is so, then you can do this:
add a calculated field to your dataset to calculate the row totals like
{ (a1+b1+c1+d1),(a2+b2+....), .... },
and then from your variable, call
SUM(Fields!CalculatedField.Value).
for above example, you can give the calculated field an expression as:
= CInt(Fields!a.Value)+CInt(Fields!b.Value)+CInt(Fields!c.Value)+CInt(Fields!d.Value)
this would make each entry in the calculated field as sum of each entry in all fields.
So sum of calculated field would give you your answer.
Hope thats what you wanted. Otherwise, well I tried understanding the problem. :)

Outer SUM needs a scope too. Try this:
=SUM(SUM(Fields!amt.Value,"Acctrange_90300_90399_InterestExpenses"),"Acctrange_90300_90399_InterestExpenses")
I expect this will also fail--in some new & different way--but that error will get you closer to a solution.

When SSRS wants to give me headaches like this, I cheat. I put the inner calculation in a hidden text box or name the box that displays it if I want it to show, then refer to it by name. So if I had the sum of the first column in a text box called txtFirstColumnSum, and the second column sum in the text box called txtSecondColumnSum, I'd use:
=cdec(ReportItems!txtFirstColumnSum.Value)+ cdec(ReportItems!txtSecondColumnSum.Value)...
Another way to do it is using the built-in scopes, but writing custom code to handle the math between the fields.
For example if I want the percentage of the current YTD sales over the same period the prior year, and also want to check for divide by zero, I can do it in an expression, but I use it on several levels, so instead I made custom code:
Public Function DeltaPercent(ByVal currentAmount as decimal,ByVal pastAmount as Decimal) as Decimal
Dim difference as decimal
Dim result as decimal
if pastAmount<>0 then
difference=currentAmount-pastAmount
result=difference/pastamount
else
result=0
end if
return result
End Function
Then to get the % change, I call it:
=Code.DeltaPercent(Sum(Fields!SalesYTD.Value, "SalesTerritory"),Sum(Fields!SalesPY1TD.Value, "SalesTerritory"))
One tip I wish I'd known sooner: If you use the syntax
ReportItems("txtFirstColumnSum").Value
you have to make sure you type it right. If you use the bang syntax (!) above, you get intellisense.

Related

Value within a function seems to not be able to detect the local variables and also fails

I want to be able to run something like the following:
f:{[dt] syms:`sym1;eval parse"select from tbl where date = dt, sym=syms"}
f[.z.D]
Given the following :
tbl:([] date:2022.01.01 2022.01.01; Id:1000000 2000000; sym:`sym1`sym2;price:10 20;qty:3 4)
f:{[dt] syms:`sym1; ?[tbl;((=;`date;`dt);(=;`sym;`syms));0b;()]}
f1:{[dt] syms:`sym1; (?) . (tbl;((=;`date;`dt);(=;`sym;`syms));0b;())}
f2:{[dt] syms:`sym1; value (?;tbl;((=;`date;`dt);(=;`sym;`syms));0b;())}
f[.z.D] // works
f1[.z.D] // Gives Error - dt not recognized/out of scope
f2[.z.D] // Gives Error - dt not recognized/out of scope
Value within a function seems to not be able to detect the local variables and surprisingly (?) . also fails. (maybe because this in itself is a function and dt is not defined here?)
Is there any work around for this?
For context, I have a function that takes a select string/functional select, parses it, does some checks and manipulations on the functional form and returns a modified functional form.
I want users to be able to call this function from their own functions and that parameters they have defined in their function can be in the outputted functional form and that functional form can be valued some how.
I don't want users to be forced to pass more variables into my function etc.
What you need to do here is remove the backtick for dt and syms
I would also recommend using a backtick when calling your table name.
Further, you should make sure syms is enlisted if it is only one symbol.
So your function should be:
f:{[dt] syms:(),`sym1; ?[`tbl;((=;`date;dt);(=;`sym;syms));0b;()]}
If you parse your select statement you can see the correct form for functional selects:
q)parse "select from tbl where date=2022.01.01,sym=`sym1"
?
`tbl
,((=;`date;2022.01.01);(=;`sym;,`sym1)) // comma in front of `sym1 means enlist
0b
()
The backtick is not needed as this is a variable, defined in your function, it would be the same as doing:
?[`tbl;((=;`date;2022.01.01);(=;`sym;enlist `sym1));0b;()]
This should allow you to use your function correctly:
q)f[2022.01.01]
date Id sym price qty
---------------------------------
2022.01.01 1000000 sym1 10 3
For more information, see the kx documentation

Splunk: How to get two searches in one timechart/graph?

I have to queries which look like this:
source="/log/ABCD/cABCDXYZ/xyz.log" doSomeTasks| timechart partial=f span=1h count as "#XYZ doSomeTasks" | fillnull
source="/log/ABCD/cABCDXYZ/xyz.log" doOtherTasks| timechart partial=f span=1h count as "#XYZ doOtherTasks" | fillnull
I now want to get this two searches in one graph (I do not want to sum the numbers I get per search up to one value).
I saw that there is the possibility to take appendcols but my trials to use this command were not successful.
I tried this but it did not work:
source="/log/ABCD/cABCDXYZ/xyz.log" doSomeTasks|timechart partial=f span=1h count as "#XYZ doSomeTasks" appendcols [doOtherTasks| timechart partial=f span=1h count as "#XYZ doOtherTasks" | fillnull]
Thanks to PM 77-1 the issue is solved.
This command works:
source="/log/ABCD/cABCDXYZ/xyz.log" doSomeTasks|timechart partial=f span=1h count as "#XYZ doSomeTasks" | appendcols[search source="/log/ABCD/cABCDXYZ/xyz.log" doOtherTasks| timechart partial=f span=1h count as "#XYZ doOtherTasks" | fillnull]
Note: You do not have to mention the source in the second search command if it is the same source as the first one.
General solution
Generate each data column by using a subsearch query in the following form:
|appendcols[search (myquery) |timechart count]
Additional steps
The list of one-or-more query columns needs to be preceded by a generated column which establishes the timechart rows (and gives appendcols something to append to).
|makeresults |timechart count |eval count=0
Note: It isn't strictly required to start with a generated column, but I've found this to be a clean and robust approach. Notably, it avoids problems that may occur in the special-case of "No results found", which otherwise can confuse the visualization rendering. Plus it's more uniform and, as a result, easier to work with.
Finally, specify each of the fields to be charted, with _time as the x-axis:
|fields _time, myvar1, myvar2, myvar3
Complete example
|makeresults |timechart span=5m count |eval count=0
|appendcols[search (myquery1) |timechart span=5m count as myvar1]
|appendcols[search (myquery2) |timechart span=5m count as myvar2]
|appendcols[search (myquery3) |timechart span=5m count as myvar3]
|fields _time, myvar1, myvar2, myvar3
Be careful to use the same span throughout.
Other hints
When comparing disparate data on the same chart, perhaps to evaluate their relative timing, it's common to have differences in type or scale that can render the overlaid result nearly useless. For cases like this, don't neglect the 'Log' format option for the Y-Axis.
In some cases, it may even be worthwhile to employ data hacks with eval to massage the values into a visual comparable state. For example, appending |eval myvar1=if(myvar1=0,0,1) deduplicates values when used following timechart count. Here's some relevant docs:
Mathematical functions
Comparison and Conditional functions

Calculations in table based on variable names in matlab

I am trying to find a better solution to calculation using data stored in table. I have a large table with many variables (100+) from which I select smaller sub-table with only two observations and their difference for smaller selection of variables. Thus, the resulting table looks for example similarly to this:
air bbs bri
_________ ________ _________
test1 12.451 0.549 3.6987
test2 10.2 0.47 3.99
diff 2.251 0.078999 -0.29132
Now, I need to multiply the ‘diff’ row with various coefficients that differ between variables. I can get the same result with the following code:
T(4,:) = array2table([T.air(3)*0.2*0.25, T.bbs(3)*0.1*0.25, T.bri(3)*0.7*0.6/2]);
However, I need more flexible solution since the selection of variables will differ between applications. I was thinking that better solution might be using either varfun or rowfun and speficic function that would assign correct coefficients/equations based on variable names:
T(4,:) = varfun(#func, T(3,:), 'InputVariables', {'air' 'bbs' 'bri'});
or
T(4,:) = rowfun(#func, T(3,:), 'OutputVariableNames', T.Properties.VariableNames);
However, the current solution I have is similarly inflexible as the basic calculation above:
function [air_out, bbs_out, bri_out] = func(air, bbs, bri)
air_out = air*0.2*0.25;
bbs_out = bbs*0.1*0.25;
bri_out = bri*0.7*0.6/2;
since I need to define every input/output variable. What I need is to assign in the function coefficients/equations for every variable and the ability of the function to apply it only to the variables that are present in the specific sub-table.
Any suggestions?

How can I use SUM(ABOVE) as part of a longer formula in Microsoft Word?

I have a table like so:
Task 1 | $59,700
Task 2 | $59,700
Task 3 | $59,700
10% Off | $xx,xxx
-------------------
Total: $xx,xxx
I'd like to use formulas in Word to calculate this.
For the first value, I'm using =SUM(ABOVE)*0.10 I would expect this to yield $17,910.
For the second value, I'm using =SUM(ABOVE)-C5 I'd expect this to yield $161,190.
Unfortunately, the first value and second value both yield $179,100 and I'm not exactly sure why. Appreciate any help and thanks for reading.
For the discount use =SUM(ABOVE) * -0.1 to give you a negative discount. Then use =SUM(ABOVE) by itself for total. Numbers work out as expected.

ssrs expression to split string possible?

so in my query i have select columnx from tblz
it returns 001.255556.84546
I want to be able to split this via '.' and put it into three columns.
column1 = 001
column2 = 255556
column3 = 84576
is this possible?
For info, in 2008 these dont work, you have to do the following:
=Split(Fields!returnedValue.Value, ".").GetValue(0)
Create three calculated fields with the following expressions:
=(Split(Fields!columnx.Value, ".")).GetValue(0)
=(Split(Fields!columnx.Value, ".")).GetValue(1)
=(Split(Fields!columnx.Value, ".")).GetValue(2)
I'm not sure it works or not, maybe give it a try. You might need to use IIF() statement to check values before getting them.
In SSRS you reference the field name, tell it the delimiter to use. Since you are not assigning to a variable, per se, you then need to tell it which part of the split string to use. In your example
=Split(Fields!returnedValue.Value,".")(0)
=Split(Fields!returnedValue.Value,".")(1)
=Split(Fields!returnedValue.Value,".")(2)
You would replace returnedValue with whatever the actual field name is, and place each one of those into your columns 1 - 3, respectively.
This answer was originally posted in the question instead of being posted as an answer:
=(Split(Fields!columnx.Value,".")).GetValue(0)
=(Split(Fields!columnx.Value,".")).GetValue(1)
=(Split(Fields!columnx.Value,".")).GetValue(2)