How to change the GETPIVOTDATA() dynamically - excel-formula

I have two formulas like below:
=GETPIVOTDATA("Sum of Values",'Input Data'!$A$4,"State",Q42,"Route",$S$1,"STAT_COMB",$G$37,"SHA",$G$35)
=GETPIVOTDATA("Sum of Values",'Input Data'!$A$4,"State",Q42,"Route",$S$1,"STAT_COMB",$G$37)
The main difference in the second formula is, I'm not considering the "SHA" parameter. To consider this or not depends on another cell value. I can write an if condition to pick the formula accordingly. But the problem is I have another situation like this:
=GETPIVOTDATA("Sum of Values",'Input Data'!$A$4,"Route",Q42,"STAT_COMB",$G$37)
Here, I'm not considering the "State" and "SHA" parameter which depends on a respective different cells whether to consider or not.
Similarly each [Field],[Item] Pair in the formula depends on respecitve different cells to include them or not.
Writing too many if conditions will make the formula cumbersome. So, I'm wondering if there is any way to dynamically omit the [Field],[Item] pairs in the formula.
I could've used INDIRECT inside the getpivotdata() but INDIRECT fetches only a single value but I need a pair of values for each parameter.

This is the best I could figure out...but it isn't necessarily pretty...
The challenge here is that you can't (to my knowledge and without VBA) dynamically change which overloaded GETPIVOTDATA function you are using in a cell. So we need to pick 1 function. In this example, here's my function:
=GETPIVOTDATA("Sum of hello",INDIRECT(K2),M1,O1,M2,O2,M3,O3,M4,O4)
I've picked an overload that specifies 4 [field,item] pairs.
Now I set up my worksheet like this...
You see -- for this example, I only want to use 2 [field,item] pairs -- so I just copy the parameters to fill in the remaining 2 pairs in the overloaded function. Excel still calculates the GETPIVOTDATA function correctly since I really have only specified 2 unique [field,item] pairs.
Does this get you far enough towards your goal?

Related

Excel: missing something in writing an enumeration function

Up front let me say I can do this in VBA but I am trying to do it without using VBA with the assistance of the new LAMBA function.
I have a list, let us say A,B,C,D,C,E,B,B
what I am trying to write is an enumeration function which gives me the individual positions of set of identical items. So in the above example it would return a list 1,1,1,1,2,1,2,3 (the last item is a three because it is the 3rd "b" element etc). It is easy enough to do in cells with the answer in the next row:
a1:a8 contain A,B,C,D,C,E,B,B
b1 contains =COUNTIF(A1:$A$1,A1) and that gets dragged across all the columns
But I need the output in a dynamic array and something like b1
=COUNTIF(A1:$A$1,A1:H1) obviously won't work.
I've also tried writing a recursive LAMBDA statement which runs through a diminishing range but that gives me VALUE errors and is pretty complex in any case.
Any suggestions?
Use Offset inside the COuNTIFS:
=COUNTIF(OFFSET(A1,0,0,1,SEQUENCE(,COUNTA(1:1))),INDEX(1:1,,SEQUENCE(,COUNTA(1:1))))
For a non Volatile version use:
=MMULT(SEQUENCE(,COLUMNS(A1:H1),1,0),(A1:H1=TRANSPOSE(A1:H1))*(SEQUENCE(,COLUMNS(A1:H1))>=SEQUENCE(COLUMNS(A1:H1))))
With LET:
=LET(x,A1:H1,y,COLUMNS(x),MMULT(SEQUENCE(,y,1,0),(x=TRANSPOSE(x))*(SEQUENCE(,y)>=SEQUENCE(y))))

Defined Names in an If then statement

I am trying to define Branches by State, example would be branches 1,2,3 are in Minnesota and branches 4,5,6 are in Iowa. So, I defined them to the corresponding state to use for my IF statement. However, when I put the defined group into my formula nothing comes back unless that C column is blank. Is there a way to make these groups work or should I try to think of different way to get my state per branch.
=IF(C4=Minnesota_BRs,"MINNESOTA","")
You can not use the IF function to check if a value is part of a range.
Try the following formula:
The VLOOKUP will check if C4 is part of Minnesota_BRs. If that's the case, ISERROR will evaluate to FALSE (and the IF formula will result in MINNESOTA).
=IF(ISERROR(VLOOKUP(C4,Minnesota_BRs,1;FALSE)),"","MINNESOTA")
EDIT in regards to the comment under the question:
If you want to check several ranges you can - as you suggest build a nested-IF formula. I think you are close, just the order is not correct. Use the following:
=IF(ISERROR(VLOOKUP(C4,Minnesota,1,FALSE)),IF(ISERROR(VLOOKUP(C4,Iowa,1,FALSE)),"","Iowa"),"Minnesota")
However, I think for your case, where you probably want to check the branches in many states, this is really efficient. You will get a terrible formula.
You might rather set up a table with all branches and states, and the use a formula that finds the value inside this multi column table, gives you the column number and then picks the state from the table header:
={INDEX(E4:G4,,MIN(IF(E5:G7=C4,COLUMN(A1:C1))))}
(Be aware that this is an array formula, type it in and leave the cell with CTRL+SHIFT+ENTER)
The formula is not easy to understand. Just that much information:
The E5:G7=C4 part inside the array function will check all values in the table and form an array that looks like this:
As you see, 5 results to TRUE. The IF function will then pick the column number (which is 2 here). The INDEX function then picks the second state name - Iowa.
I hope that is somewhat useful for you.

Use INDEX/MATCH to select formula written as string, and enable it?

I have a pricelist, with currently 5 different categories of products. Each product will have to have two different prices. Depedning of the product and the type of price, the calculation will be different. Therefor I've used INDEX/MATCH to find the formula needed, from a table I created.
Below a screendump, and I wanted to attach the Excel fil, but canøt seem to work out how.
Question: HOW do I then "run" the formula I fetched? -I've tried different suggestions on using EVALUATION, but it doesn't seem to cut it? Also I've tried "Indirect' on the whole formula, without success.
I would like to avoid any VBA for this case.
Can anybody provide some insight?
You could but if I understand properly, the only thing changing in the formulas is the "muliplier" number, then it's better to lookup that number instead of the whole formula. The other method (which would use Evaluate etc) is not be considered "good practice" for a number of reasons.
EDIT:
I didn't see the 2nd varying value (since I was on the SO mobile app) but it's still not an issue since it would a target column. You could be thinking of the opposite: sometimes lookups based on multiple criteria can get complicated, but this a matter of more data, as opposed to adding criteria for the lookup.
VLookup would have been the simplest method, like G2 could have been:
=VLOOKUP(E2, $J$4:$L$8, 2, False)
...to return the second column of range J4:L8 where the first column equals E2. (Then for the next required column, same formula except with 3 instead of 2.)
Since I wasn't sure more columns could be added one day, I allowed for that by, instead of specifying "Column 2 or 3" etc, it finds the column dynamically by name. (So the multiplier/factor used in G2 will change if you change the title in G1 to the name of a different column existing in the target data chart.
For the sake of neatness as well as potential of additional columns like G & H, I moved the lookup table to a separate sheet. It can stay out of the way since you won't need to see or change it very often. (If the same chart was going to be referenced by many workbooks, you could even move it to a separate workbook and point all formulas at that, since it's always best to have one copy of identical data instead of many in different workbooks.
Also to assist with potential future changes (and just to be tidier), instead of referring to the target table range addresses (like "J4:L8" etc) I named two ranges:
the table of multiplier/factor data can be referred to by it's address, or by myMultipliers
the titles of the same table is also called myMultiplierTitles (used to match to the titles of column G & H on the original sheet.
Formula
After those changes, the lookup formula in G2 is:
=INDIRECT(VLOOKUP($E2,myMultipliers,MATCH(G$1,myMultiplierTitles,0),FALSE)&ROW())*VLOOKUP($E2,myMultipliers,MATCH(G$1,myMultiplierTitles,0)+1,FALSE)
INDIRECT returns the value of a cell that you refer to by name (text/string) as opposed to directly (as a range). For example:
=INDIRECT("A1")
returns the same as
=A1
...but with INDIRECT we can get the name from elsewhere (a cell, function or formula). So if x="A1" then =INDIRECT(x) returns the same as the 2 above examples.
Your original plan of storing the entire formula in a table as text would have worked with the help of INDIRECT and/or EVALUATE but I think this way is considered better practice partly because it facilitates easier future expansion.
The formula is longer than it would have been, but that's mostly because it's dynamically reading the field names. And size doesn't matter. :-)

Avoiding duplicate long expressions in Excel

I often find myself writing Excel formulas that have something like this in the formula:
= IF(<long expression>=<some condition>,<long expression>,0)
Is there any way to accomplish this without needing to type out <long expression> twice (and also without using helper cells)?
Ideally, something that works similar to IFERROR, i.e.
= IFERROR(<some expression>,0)
This checks if <some expression> would return any type of error, and if it doesn't, it automatically returns <some expression> (without needing to again explicitly type it out a second time).
Is there an Excel function (or combination of Excel functions) similar to IFERROR but instead of checking an error condition, it checks a general (user-defined) condition based on the formula?
When it comes to formula efficiency and calculation speed, using helper cells can be of great value, even if they may initially muck up the spreadsheet design.
Put calculations into a helper cell and refer to the helper cell in the IF statement. That way the calculation will only happen once.
This method is preferred by spreadsheet auditors over the alternative of packing everything into one formula, because it is also much easier to follow and pick apart.
With careful spreadsheet planning you can house helper cells in a different (hidden) sheet or in columns that you hide to tidy up the design.
This answer applies to Excel 365 as of March 2020. A new function is now available in Insider builds of Excel. It is called LET() and is used to define, and assign a value to, a variable that can then be used multiple times inside the braces of the LET() function.
Example:
=LET(MyResult,XLOOKUP(C1,A1:A3,B1:B3),IF(MyResult=0,"",MyResult))
The first parameter is the name of a new variable, MyResult. The variable is assigned a value with the second parameter. This can be a constant, like a number or a text, or like in this case, a formula.
The third parameter is a calculation that can use the variable value.
In the following screenshot, the Xlookup returns a 0 because the found cell is empty.
In the next formula down, the Xlookup is wrapped in an IF statement, evaluated, and then repeated. This is the approach where the calculation is duplicated, as described in the question.
The third formula shows the LET() function and its result.

Using Named Range as single cell references in formulas that accept arrays

So background first, question second.
I recently discovered an interesting property of named ranges that I'm experimenting with and not finding much help. The property is this: If I name a range (a column in this example), I can use the named range as a reference in formulas and it will usually resolve as though it were a reference to the same relative position as the current cell within the named range. So if I call A:A "Alphabet" and it contains letters a through z, each in their own row, I can simply type =Alphabet in cell b26 and it will evaluate to "z" (i.e. A26 instead of a:A). Seems simple, but it is shaping up to be quite powerful, because there is essentially an index function built-in. Very useful for making tidy formulas.
Onto the issue: when I use this same technique with a range that accepts an array argument (i.e. MAX, EOMONTH, etc.), the reference is resolving in the standard way (Max(A:A)). If I wrap the reference in VALUE(), then it resolves to just the single reference within the larger range (a26). The question is simply can anyone think of any way to avoid needing to do this, or at least to make the wrapper as unobstrusive as possible?
Real world example: I have a list of employees and I want to determine which date from three named ranges is larger. So I have something like
='DateSameRow1' > Max('DateSameRow2','DateSameRow3','DateSameColumn', and it is resolving as =a10 > Max(b:b,c:c,2:2). Note the issue: The named range outside of MAX resolved one way, and inside MAX resolved another. Sure, I could just write = a10 > Max(b10,c10,d2) or whatever, but this is so much more readable in what will end up being a huge formula. Right now I'm having to write MAX(VALUE('DateSameRow2')) or whatever to get the result I want and it is defeating the purpose.
Thanks
You can use --NAMED_RANGE in front of the "offending" named range and it will force a negative VALUE and then undo the negative.
Per my comment, I would recommend you not build a spreadsheet on this functionality. The -- is even further removed from VALUE in indicating that a named range is being used in this way.

Resources