Summing up a related table's values in PowerPivot/DAX - excel

Say I have two tables. attrsTable:
file | attribute | value
------------------------
A | xdim | 5
A | ydim | 6
B | xdim | 7
B | ydim | 3
B | zdim | 2
C | xdim | 1
C | ydim | 7
sizeTable:
file | size
-----------
A | 17
B | 23
C | 34
I have these tables related via the 'file' field. I want a PowerPivot measure within attrsTable, whose calculation uses size. For example, let's say I want xdim+ydim/size for each of A, B, C. The calculations would be:
A: (5+6)/17
B: (7+3)/23
C: (1+7)/34
I want the measure to be generic enough so I can use slicers later on to slice by file or attribute. How do I accomplish this?
I tried:
dimPerSize := CALCULATE([value]/SUM(sizeTable[size])) # Calculates 0
dimPerSize := CALCULATE([value]/SUM(RELATED(sizeTable[size]))) # Produces an error
Any idea what I'm doing wrong? I'm probably missing some fundamental concepts here of how to use DAX with relationships.

Hi Redstreet,
taking a step back from your solution and the one proposed by Jacob, I think it might be useful to create another table that would aggregate all the calculations (especially given you probably have more than 2 tables with file-specific attributes).
So I have created one more table that contains (only) unique file names, and thus the relationships could be visualized this way:
It's much simpler to add necessary measures (no need for calculated columns). I have actually tested 2 scenarios:
1) create simple SUM measures for both Attribute Value and File Size. Then divide those two measures and job done :-).
2) use SUMX functions to have a bit more universal solution. Then the final formula for DimPerSize calculation could look like this:
=DIVIDE(
SUMX(DISTINCT(fileTable[file]),[Sum of AttrValue]),
SUMX(DISTINCT(fileTable[file]),[Sum of FileSize]),
BLANK()
)
With [Sum of AttrValue] being:
=SUM(attrsTable[value])
And Sum of FileSize being:
=SUM(sizeTable[size])
This worked perfectly fine, even though SUMX in both cases goes over all instances of given file name. So for file B it also calculates with zdim (if there is a need to filter this out, then use simple calculate / filter combination). In case of file size, I am using SUMX as well, even though it's not really needed since the table contains only 1 record for each file name. If there would be 2 instances, then use SUMX or AVERAGEX depending on the desired outcome.
This is the link to my source file in Excel (2010).
Hope this helps.

You look to have the concept of relationships OK but you aren't on the right track in terms of CALCULATE() either in terms of the structure or the fact that you can't simply use 'naked' numerical columns, they need to be packaged in some way.
Your desired approach is correct in that once you get a simple version of the thing running, you will be able to slice and dice it over any of your related dimensions.
Best practice is probably to build this up using several measures:
[xdim] = CALCULATE(SUM('attrstable'[value]), 'attrstable'[attribute] = "xdim")
[ydim] = CALCULATE(SUM('attrstable'[value]), 'attrstable'[attribute] = "ydim")
[dimPerSize] = ([xdim] + [ydim]) / VALUES('sizeTable'[size])
But depending on exactly how your pivot is set up, this is likely to also throw an error because it will try and use the whole 'size' column in your totals. There are two main strategies for dealing with this:
Use an 'iterative' formula such as SUX() or AVERAGEX() to iterate individually over the 'file' field and then adds up or averages for the total e.g.
[ItdimPerSize] = AVERAGEX(VALUES('sizeTable'[file]), [dimPerSize])
Depending on the maths you want to use, you might find that produce a useful average that you need to use SUMX but devide by the number of cases i.e. COUNTROWS('sizeTable'[file]).
You might decide that the totals are irrelevant and simply introduce an error handling element that will make them blank e.g.
[NtdimPerSize] = IF(HASONEVALUE('sizeTable'[file]),[dimPerSize],BLANK())
NB, all of this assumes that when you are creating your pivot that you are 'dragging in' the file field from the 'sizetable'.

Related

Nested IF(AND(OR statement

Here is my current formula
=IF(OM2=0,"No",IF(OM2=4(OR(5,11,12,16,17))*AND(F2="Double"),"Yes",IF(OM2=1(OR(2,3,6,7,8,9,10,13,14,15))*AND(F2="Triple"),"Yes","No")))
I'm trying to get OU to be yes if OM is 4,5,11,12,16,or 17 and F is Double.
Also, to get OU to be yes if OM is 1,2,3,6,7,8,9,10,13,or 15 and F is Triple.
I have checked F2 and it correctly results "Double" or "Triple" accordingly with correct spelling and no extra spaces.
I am still getting "No" being resulted, see pic below:
Thanks for any help!
Try to write OR(OM2 = x, OM2=y, OM2 = z ...) instead of what you wrote.
This should work.
As the other responders said you should really think about making a lookup tables.
In addition, if you use Excel 2013 onwards, it is much easier if you convert your normal table into "Excel" table (Ctrl - T will do it). Google more about "Excel tables" to learn about their benefits vs traditional tables.
After that, set up 2 lookup tables, Table 1 and Table 2 (they themselves should also be Excel tables) as in the photo.
Then your formula will be:
=OR(SUMPRODUCT(--(Table1[OM]=[#OM]),--(Table1[F]=[#F])),SUMPRODUCT(--(Table2[OM]=[#OM]),--(Table2[F]=[#F])))
When you write up this formula, you can just select the cells in the respective lookup tables, Excel will automatically turn them into table named ranges as you see above.
Another option would be to use a lookup table to map your value of OM to the expected value of OU.
For example, if you had a sheet named "Lookup" with the following data:
| A | B
1 | 1 | Triple
2 | 2 | Triple
...
5 | 5 | Double
Then you could use something like
IF(VLOOKUP(OM2,Lookup!$A$1:$B$16,2,FALSE)=OU2,"Yes","No")

How to do a calculation by evaluating several conditions?

I have this table in access called invoices.
It has a field that performs calculations based on two fields. that is field_price*field_Quantity. Now I added two new columns containing the unit of measure for field_weight and field_quantity named field_priceUnit and field_quantityUnit.
Now instead of just taking the multiplication to perform the calculation, I want it to see if the units of measures match, it doesn't match then it should do a convertion of the field_quantity into the unit of measure of field_priceUnit.
example:
Row1:
ID:1|Field_Quantity:23|field_quantityUnit:LB|Field_weight:256|field_priceunit:KG|field_price:24| Calculated_Column:
the calculated_column should do the calculation this way.
1. if field_quantityunit=LB and field_priceunit=LB then field_quantity*field_price
else
if field_quantityUnit=LB and field_priceUnit=KG
THEN ((field_quantity/0.453592)*field_price) <<
Please help me.
I have to do this for multiple conditions.
Field_priceunit may have values as LB,KG, and MT
Field_quantityUnit may have field as LB,KG, and MT
if both units don't match, then I want to do the conversion and calculate based on the new convetion as seen in the example.
Thank you
The following formula should get you running if your units are only lb and kg and you only have to check one direction:
iif(and(field_quantityunit='LB', field_priceunit='LB'), field_quantity*field_price, (field_quantity/0.453592)*field_price)
This doesn't scale well though as you may have to convert field_price or you may add other units. This iif formula will grow WAY out of hand quickly.
Instead create a new table called unit_conversion or whatever you like:
unit | conversion
lb | .453592
kg | 1
g | 1000
mg | 1000000
Now in your query join:
LEFT OUTER JOIN unit_conversion as qty_conversion
ON field_quantityunit = qty_conversion.unit
LEFT OUTER JOIN unit_conversion as price_conversion
On field_priceUnit = price_conversion.unit
Up in your SELECT portion of the query you can now just do:
(field_quantity * qty_conversion.conversion) * (field_price * price_conversion.conversion)
And you don't have to worry what the units are. They will all convert over to a kilogram and get multiplied.
You could convert everything over to a pound or really any unit of weight here if you want but the nice thing is, you only need to add new units to your conversion table to handle them in any sql that you write this way so it's very scalable.

sum values of cells in google sheets if the result of their sum with adjacent cell meets a condition

Suppose I have the following data in a spreadsheet, where the first row contains the column headings and the first column contains the row index (for reference):
||A | B | C |
==||================
0 ||2 | 3 | Y |
--||----------------
1 ||2 | 4 | Y |
--||----------------
2 ||3 | 5 | N |
--||----------------
3 ||8 | 3 | Y |
--||----------------
How can I get the sum of all the values in column B for which b - a >= 1 && c == "Y", in Google Sheets and Excel?
So essentially, the sum should factor in only rows 0 and 1 in which case the result should be 7.
I know this sounds like a very specific question but I did not know how else to describe it other than by example. The answer should be applicable in other similar scenarios.
Thanks for the help.
[Edit] In response to people voting down due to lack of research, well, I've tried to use the sumif() function but I got stuck immediately on the condition part as I am not sure how to compare the current item in the aggregation with another cell. I also tried to use the sumifs() function which allows for multiple criteria, but also to no avail. As for my research, I searched on Google but could not find anything, possibly due to my inability to express the requirement in a manner suitable for a google query. Therefore, I have presented the above as a way of explaining my requirement by example.
I hope this helps.
I appreciate that this may not be possible to do with the simple built in formulas. If this is the case, please mention it as that would also be useful to know.
Thank you.
Excel: =SUMPRODUCT(((B:B-A:A)>=1)*(C:C="Y")*(B:B))
Untested, but let me know if it works. Next time, remember to add an example of code/formulas that you have already tried and what error you ran into.
Edit:
Tested it, here is a screenshot of it working with your example data (disregard the fact that my Excel is in spanish)
This works by intersecting both logical tests (that is, performing a logical AND): (B-A)>=1 AND C="Y". Here you can see the result of each logical test and then, finally, where it evaluates to TRUE it returns the value in column B; where it's FALSE, it returns 0. Finally, it sums the values in the result array.

PowerPivot Calculated Column Circular Dependency

I'm really spinning my wheels on this one. I'm trying to add 2 calculated columns in a Power Pivot table (in Excel 2013) to a loaded single column.
Setup (just first row shown):
Prd | Beg | End
1 | =CALCULATE(SUM([End]),Table[Prd]=EARLIER([Prd])-1) | =[Beg]+[Prd]
I want it to calculate like this:
Prd | Beg | End
1 | 1 | 2
2 | 2 | 4
3 | 4 | 7
But no matter what I do, I get a circular reference error because the [End] calculation is pointing to the [Beg] calculation and vice versa. I'm trying to get it to perform a rolling calculation where the [Beg] amount always equals the [End] amount from the prior [Prd].
I tried various calculations using SUMX and ALLEXCEPT, but I'm not getting this one right. I even tried designating the Row Identifier in the Table Behavior tab based on this but it's not working with that either.
Appreciate any suggestions!
I would suggest you to base your formula for [Beg] column on previous values of [Prd] column. Therefore
Beg=SUMX(
FILTER(
ALL(Table[Prd]),
Table[Prd] < EARLIER(Table[Prd])
),
Table[Prd]
) + 1
Explanation:
It sums up all the previous values for [Prd] column and adds 1 (if you take a look at the generated values, you'll see the pattern).
But the formula for [End] should also be fixed so you won't run into the same exception. So you'll have the following (this will sum values from current row for [Beg] and [Prd]):
End=SUMX(
FILTER(
ALL(Table[Beg], Table[Prd]),
Table[Prd]=EARLIER(Table[Prd])),Table[Beg]
) + Table[Prd]
Explanation:
In your case, avoiding to use CALCULATE and using instead just SUMX and EARLIER for [End] will help you to get rid of circular dependency.

Creating a limited drop-down List

So say I have a table x by y entries.
X is far too great, or changes often enough, that making X additional tables/lists/named ranges is absurd.
However, I need to make a drop-down list of some of y.
Specifically:
Name | A | B | C | ..
Yannis| 20 |Yellow| Green| ..
Mirrah| 400 |Purple|Yellow| ..
.
.
.
I need a drop-down select of Name to change the options in a different drop-down list, which is based off of B & C.
Normally you can do this with either a Filter or INDIRECT(). However, it is beyond unreasonable to create a unique table, or name define, for each entry in X.
It is possible to create a table with all the possible entries for B & C, if there was a way to filter a named define for a list based off of the first table (using vlookup(), most likely)
In layman's terms: I need list 1 to filter list 2 where list 1 is either enormous or subject to constant change.
Gah, so this:
=INDIRECT("'InfoDump'!" & ADDRESS(MATCH(C5,PkmList,0)+25,10))
put into the data validation list works, however it's only one entry, and I need 3.
simply adding commas and copies causes error messages.
The one entry that this supplies is correctly referenced (dynamically) from the table without any need for more tables/namedRanges.
C5 is where the first list is
PkmList is the NamedRange for the first column of the Table
+25 'cause the table starts at A25 (column title)
10 referencing the first of 3 columns I need in the second list.
Okay!
After some experimentation, this accomplishes what I was looking for:
=INDIRECT("'InfoDump'!" & (ADDRESS(MATCH(C5,PkmList,0)+25,10)) & ":" & ((ADDRESS(MATCH(C5,PkmList,0)+25,12))))
or, in some different terms:
=INDIRECT("'sheetName'!" & (ADDRESS(MATCH(DropDownOne,DropDownOneCriteria,0)+(AdjustRow),(AdjustColumn))) & ":" & ((ADDRESS(MATCH(DropDownOne,DropDownOneCriteria,0)+(AdjustRow),(AdjustColumn)))))
Data validation hates logic.
-
In the most basic sense:
Match(a,b,c) gets the location of 'a' in 'b' (c is the same as vlookup's exact match option)
Address(row,column) gets the "j26" address, you can (as I did) adjust from where you found the match. (in my case, 25 down 'casue the table actually started at A25, but the list started at '1'; then 10 - 12 across for the 3 options I needed to list)
indirect(txt) turns this into a list. more or less. use "'sheetName'!" for referencing a different sheet.
-
So in the end this gives you a "=A2:A4" in the Data validation bar, based on another list. Same as using the popular work around that is the fruit vegetable cabbage example, but this doesn't require you to make multiple named ranges. (Which means it works for a single large changing table).

Resources