I am new to powerbi and trying to understand difference between CALCULATETABLE and CALCULATE. I read these 1,2 pages. I am not clear. It says that Whereas the CALCULATE function requires as its first argument an expression that returns a single value, the CALCULATETABLE function takes a table of values. Could anyone explain it further?
update 1
1) it seems that CALCULATETABLE works on a table of data while CALCULATE works on a single value. is there any difference in terms of output?
2) could anyone guide when it is better to use one of these functions over other?
These are the most fundamental function in DAX. Thy are used when you need to change the context where the expression (first parameter of the function) is evaluated.
The difference between the two functions is related to the input type and the output type.
CALCULATE function takes as input an expression that evaluates to scalar and returns a scalar value.
CALCULATETABLE function takes as input an expression that evaluates to table and returns a table.
Therefore, if you need to change the context where a scalar expression is evaluated, use CALCULATE. If you need to change the context where a table expression is evaluated, use CALCULATETABLE.
Expressions
An expression that evaluates to scalar is everything that returns you a scalar. For example, SUM(), MIN(), MAX() they all returns you a single value.
An expression that evaluates to table is everything that returns you a table. For example, 'My Table'[My Field] and VALUES('My Table'[My Field]) both returns you a table.
Sources
Finally, how can you know input type and output type of dax functions? My favourite source is dax.guide
Related
I have to convert some SAS code. In other programming languages I am used to < being used in comparisons e.g. in pseudo-code: If x < y then z
In SAS, what is the < operator achieving here:
intck(month,startdate,enddate)-(day(enddate)<day(startdate))
I have been able to understand the functions using the reference documentation but I can't see anything relating to how '<' is being used here.
Just to go into a little more detail about what the code you have there is doing, it's an old school method to determine the number of months from one date to the next (possibly to calculate a birthday, for example).
Originally, SAS functions intck and intnx only calculated the number of "firsts of the month" in between two dates (or similar for other intervals). So INTCK('month','31OCT2020'd, '01NOV2020'd) = 1, while INTCK('month','01OCT2020'd,'30NOV2020'd) = 1. Not ideal! So you'd add in this particular bit of code, -(day(enddate)<day(startdate)), which says "if it is not been a full month yet, subtract one". It's equivalent to this:
if day(enddate) < day(startdate) then diff = intck(month,startdate,enddate) - 1;
else diff = intck(month,startdate,enddate);
There's now a better way to do this (yay!). intck and 'intnx' are a bit different, but it's the same idea. For intck the argument is method, where c for "continuous" is what you want to compare same period in the month. For intnx it is the alignment option, where 's' means "same" (so, move to the same point in the month).
So your code now should be:
intck(month,startdate,enddate,'c')
The symbol < is an operator in that expression. It is not a function call , like INTNX() is in your expression.
SAS evaluates boolean expressions (like the less than test in your example) to 1 for TRUE and 0 for FALSE.
So your expression is subtracting 1 when the day of month of ENDDATE is smaller than the day of month of STARTDATE.
Note: You can also do the reverse, treat a number as a boolean expression. For example in a statement like:
if (BASELINE) then PERCENT_CHANGE = (VALUE-BASELINE) / BASELINE ;
A missing value or a value of zero in BASELINE will be treated as FALSE and so in those cases the assignment statement does not run.
For a dataset in SSRS reports, I've created a calculated field with below expression and it works fine.
=(Fields!SalesAmount.Value+Fields!TaxAmt.Value)*Fields!Factor.Value
But sometime we can have factor value as 0. So, I modified above expression with below:
=iif(Fields!Factor.Value = 0,(Fields!SalesAmount.Value+Fields!TaxAmt.Value)*1,(Fields!SalesAmount.Value+Fields!TaxAmt.Value)*Fields!Factor.Value)
But this throws below exception:
The Value expression for the textrun ‘Textbox2.Paragraphs[0].TextRuns[0]’ uses an aggregate function on data of varying data types. Aggregate functions other than First, Last, Previous, Count, and CountDistinct can only aggregate data of a single data type.
Can someone please help to get resolve this issue?
This doesn't seem to be an issue with the IIF, but the datatypes seem to be mismatched. I have a few suggestions to try. First, you could try to multiply the true value by 1.0 as I assume the datatypes are decimal or double. The other option would be to use something like CInt to covert the value to the correct datatype. CInt would likely be inappropriate for decimals as it would round off any decimal values, but the idea is the same. Since your expression doesn't use any aggregates and only uses normal operators, it must relate to something other than the IIF.
Here's a useful link to break down the datatypes and conversion methods. Choose the most appropriate conversion and apply it to the 1.
EDIT: The expression should be the following.
=iif(Fields!Factor.Value = 0.00,
(Fields!SalesAmount.Value+Fields!TaxAmt.Value)*CDbl(1),
(Fields!SalesAmount.Value+Fields!TaxAmt.Value)*Fields!Factor.Value)
I have three column as A, B, C
I'm writing an expression for column D in Qlikview to find out whenever column B & C IsNull I need to replace the value of C in column D. Similarly Vice versa for the remaining columns.
Expression:
=if((IsNull(A) and IsNull(B)), C,if((IsNull(B) and IsNull(C)), A,.....)
But I'm not getting the values in my output.
Was there any issue in the above expression ?
Can someone help me on it .
try
if (rangesum(len(A),len(B))=0,C,if (rangesum(len(B),len(C))=0,A,.....
isNull is a problematic functions and many times does behave as expected.
It is best practice to use Len() instead.
also make sure you have a single value in A,B,C per row, otherwise it will not work
In IF statement is it possible to return the value of the parameter of the logical expression with some keywords instead of rewriting the parameter?
The reason is that for nested if statements it would be very useful.
I've tried to explain it as better as possible in English but I suppose that the best way is an example.
An example is:
This is using the parameter of the logical expression:
=IF('MySecondSheet'!C21>0, 'MySecondSheet'!C21, false)
This is the same but using an hypothetical keyword that I will call "this"
=IF('MySecondSheet'!C21>0, this, false)
Is it possible in some way?
Thanks,
I don't think this is possible. In fact, I don't think it would be sensible to develop such functionality because it is a very particular use case. Suppose you were comparing with another cell value instead of a constant.
=IF('MySecondSheet'!C21>'MyfirstSheet'!A1, this, "text")
Which value would this refer to now? Furthermore, suppose you have a more complicated formula
=IF(A1 * A1 - A2 < A3, this, "text")
Again, it is not obvious whether this would return the left-hand side of the relation or one of the cell values.
If you name C21 in MySecondSheet this then something like:
=IF(this>0,this,"false")
should work.
I'm trying to figure out if there is a macro similar to delay in clojure to get a lazy expression/ variable that can be evaluated later.
The use case is a default value for Map.get/3, since the default value comes from a database call, I'd prefer it to be called only when it's needed.
Elixir's macro could be used for writing simple wrapper function for conditional evaluation. I've put one gist in the following, though it may be better/smarter way.
https://gist.github.com/parroty/98a68f2e8a735434bd60
"Generic" laziness is a bit of a tough nut to crack because it's a fairly broad question. Streams allow laziness for enumerables but I'm not sure what laziness for an expression would mean. For example what would a lazy form of x = 1 + 2 be? When would it be evaluated?
The thought that comes to mind for a lazy form of an expression is a procedure expression:
def x, do: 1 + 2
Because the value of x wouldn't be calculated until the expression is actually invoked (as far as I know). I'm sure others will correct me if I'm wrong on that point. But I don't think that's what you want.
Maybe you want to rephrase your question--leaving out streams and lazy evaluation of enumerated values.
One way to do this would be using processes. For example the map could be wrapped in a process like a GenServer or an Agent where the default value will be evaluated lazy.
The default value can be a function which makes the expensive call. If Map.get/3 isn't being used to return functions you can check if the value is a function and invoke it if it is returned. Like so:
def default_value()
expensive_db_call()
end
def get_something(dict, key) do
case Map.get(dict, key, default_value) do
value when is_fun(value) ->
value.() # invoke the default function and return the result of the call
value ->
value # key must have existed, return value
end
end
Of course if the map contains functions this type of solution probably won't work.
Also check Elixir's Stream module. While I don't know that it would help solve your particular problem it does allow for lazy evaluation. From the documentation:
Streams are composable, lazy enumerables. Any enumerable that generates items one by one during enumeration is called a stream. For example, Elixir’s Range is a stream:
More information is available in the Stream documentation.
Map.get_lazy and Keyword.get_lazy hold off on generating the default until needed, links the documentation below
https://hexdocs.pm/elixir/Map.html#get_lazy/3
https://hexdocs.pm/elixir/Keyword.html#get_lazy/3
You can wrap it in an anonymous function, then it will be evaluated when the function is called:
iex()> lazy = fn -> :os.list_env_vars() end
#Function<45.79398840/0 in :erl_eval.expr/5>
iex()> lazy.()