SUMIF in a closed workbook - excel

I got the following working formula:
={SUM(SUM.IF(
'Sheet1'!$B:$B;
IF(INDEX(List;;MATCH($D$4;Month;0);2);INDEX(List;;1);0);
'Sheet1'!$H:$H
))}
I would like to make it working if the ranges (Sheet1) are actually in a closed workbook. I found the following article:
http://support.microsoft.com/kb/260415
I don't know where to start to make it working assuming B:B and H:H are in another workbook.
D4 is the current month, Month is a list with the 12 months and List is composed of 2 zones, the first one with unique IDs that I need to compare with the B:B range and the second zone with 12 booleans columns telling me if I actually want to consider that ID for the desired month.
If I just convert it using the Microsoft KB, the following won't work (#N/A! error if entered as an array formula and I just get the total number of lines of the sheet if I enter it as a normal formula):
={SUM(IF(
'[myFile.xlsx]Sheet1'!$B:$B = IF(INDEX(List;;MATCH($D$4;Month;0);2);INDEX(List;;1);0);
'[myFile.xlsx]Sheet1'!$H:$H;
0
))}
After #barry houdini's answer, here are the exact formulas I have (still a little bit simplified). The second one (his answer) doesn't give me the exact same number because it does add up the numbers in the H columns where the B column is empty (even if List doesn't have any empty rows).
Working
=SUM(SUMIF(
'April'!$B:$B;
IF(INDEX(List;;4;2);INDEX(List;;1);0);
'April'!$H:$H
))
Almost working
=SUM(
IF(
ISNUMBER(
MATCH('April'!$B:$B;IF(INDEX(List;;4;2);INDEX(List;;1);0);0)
);
'April'!$H:$H
))

Your problem is that Excel doesn't know how to compare a whole column...
'[myFile.xlsx]Sheet1'!$B:$B
to a differently sized list, i.e. that returned by
IF(INDEX(List;;MATCH($D$4;Month;0);2);INDEX(List;;1);0)
Try using MATCH to do that, i.e.
revised as per comments:
=SUM(IF('[myFile.xlsx]Sheet1'!$B:$B<>"",IF(ISNUMBER(MATCH('[myFile.xlsx]Sheet1'!$B:$B;IF(INDEX(List;;MATCH($D$4;Month;0);2);INDEX(List;;1);0);0));'[myFile.xlsx]Sheet1'!$H:$H)))
or alternative.....(see comments) which avoids the extra IF
=SUM(IF(ISNUMBER(MATCH('[myFile.xlsx]Sheet1'!$B:$B;IF(INDEX(List;;MATCH($D$4;Month;0);2);INDEX(List;;1);"");0));'[myFile.xlsx]Sheet1'!$H:$H))
confirmed with CTRL+SHIFT+ENTER
MATCH returns a number (when there's a match) or #N/A so when you wrap that in ISNUMBER you get a list of TRUE/FALSE values as required.
Note: this will probably be slow using whole columns B and H (SUMIF will only use the "used range", this will use the whole column) so, if you can, I recommend using a more limited range

I'm guessing that list and months are named ranges in the closed workbook. This being the case you cannot reference named ranges in a closed workbook. Convert your use of List and Month to actual cell references in the closed workbook.

Related

Multiply based on condition then sum results ( multiply if empty <> ) in google sheets

I need help in writing a formula in cell b7. The formula must look to the right and multiply the nonempty cells by the corresponding value in row 3, and I would like to sum up the results.
File link provided.
FILE LINK
ScreenShot
Please see my comment to your original post.
That said, I will try to explain how to approach this as I think you intend. (This solution will be a Google Sheets solution which will not work in Excel.)
The first thing you will need to do is to delete everything from Row 11 down: all of your examples and notes must be deleted for the following proposed formula to work correctly.
Once you have no superfluous data below your main chart, delete everything from B6:B (including the header "Total").
Then, place the following formula in cell B6:
={"TOTAL"; FILTER(MMULT(C7:G*1, TRANSPOSE(C$3:G$3*1)), A7:A<>"")}
This formula will return the header text "TOTAL" (which you can change within the formula itself if you like) followed by the calculation you want for each row where a name is listed in A7:A.
MMULT is a difficult function to explain, but it multiplies one matrix ("grid") or numbers by another matrix ("grid") and returns the sum of all products per row (or per column, depending on how you set it up) —— which is what you are trying to do.
MMULT must have every element of both matrices be a real number. To convert potential nulls to zeroes, you'll see *1 appended to each range (since null times 1 is zero).
This assumes that all data entered into C7:G and C3:G3 will always be either a number or null. If you enter text, you'll throw the formula into an error. If you think accidental text entries in those ranges are possible, use this version instead:
={"TOTAL"; FILTER(MMULT(IFERROR(C7:G*1, ROW(C7:G)*0), TRANSPOSE(IFERROR(C$3:G$3*1, COLUMN(C$3:G$3)*0))), A7:A<>"")}
The extra bits use IFERROR to exchange error-producing entries with zeroes, since MMULT must have every space in both matrices filled with a real number.

Issue converting SUMPRODUCT formula to INDEX+MATCH

I have a spreadsheet that shows the actual dollars produced and the expected dollars produced for each employee, where each row is one day and each employee has two columns. I would like to count the number of times an employee came within 10% of their production goal without referencing specific columns. Please look at the example spreadsheet.
I want for the formulas in cells Sheet2!E4:E7 to do what the formulas in Sheet2!E10:E13 do.
I am trying to avoid using direct column references because it causes me to have to go in and update the columns in the formulas every time a new employee is added to the sheet.
I'm no stranger to using INDEX+MATCH, or to converting SUMPRODUCT formulas to INDEX+MATCH. What I can't get past are the formulas in cells Sheet2!E4:E7. If you evaluate the formula you can watch the INDEX+MATCH section on the left side of the formula work correctly, and then a nearly identical INDEX+MATCH section on the right side evaluate to 0 for no apparent reason.
The formula I'm having trouble with is in cell Sheet2!E4:
COUNTIF(INDEX(Sheet1!$A$2:$AZ$314,,MATCH($B4,Sheet1!$A$1:$AZ$1,0)),">"&(INDEX(Sheet1!$A$2:$AZ$314,,MATCH($B4,Sheet1!$A$1:$AZ$1,0)+1)))
The section to the left of the ">" will match with the correct range (Sheet1!B2:B314), however the section to the right of the ">" will evaluate to 0 instead of Sheet1!C2:C314.
This is strange to me because the only real difference between the two sections is the '+1' on the end of the MATCH function, and adding the '+1' to the section to the left of the ">" produces the expected result for the MATCH function (Sheet1!C2:C314) as seen by evaluating the formula in cell Sheet2!E5.
The formula that produces the correct result is in cell Sheet2!E10:
SUMPRODUCT(--(ISNUMBER(Sheet1!$B$2:$B$313)),--(Sheet1!$B$2:$B$313<Sheet1!$C$2:$C$313),--(Sheet1!$B$2:$B$313>=Sheet1!$C$2:$C$313*0.9))
I understand that if I exclude the '$' before the column references, any future additions/subtractions to the columns on Sheet1 will adjust the references accordingly. This solution is not ideal, because there are multiple data sheets (one for each year) where the columns are all different (Dan is column F for 2019, G for 2018, M for 2017, etc.), and the tables using these sheets are laid out in a way that would prevent me from easily being able to auto-update the formulas, so a solution that locates the correct column using the employee's name is preferred.
The correct result should be 2 for Allen and 3 for Torres, but I can only seem to get the INDEX+MATCH formulas to return 0, 12, 15, 16, or 17 (depending on what tweaks I make to the formula).
Any help with this would be greatly appreciated.
You can try this: ARRAY FORMULA CTRL + SHIFT + ENTER
=SUM(IF(ISNUMBER(INDEX($A$1:$E$30,2,MATCH(G9,$A$1:$E$1,0)):INDEX($A$1:$E$30,30,MATCH(G9,$A$1:$E$1,0))),INDEX($A$1:$E$30,2,MATCH(G9,$A$1:$E$1,0)):INDEX($A$1:$E$30,30,MATCH(G9,$A$1:$E$1,0))<INDEX($A$1:$E$30,2,MATCH(G9,$A$1:$E$1,0)+1):INDEX($A$1:$E$30,30,MATCH(G9,$A$1:$E$1,0)+1)*(INDEX($A$1:$E$30,2,MATCH(G9,$A$1:$E$1,0)):INDEX($A$1:$E$30,30,MATCH(G9,$A$1:$E$1,0))>=INDEX($A$1:$E$30,2,MATCH(G9,$A$1:$E$1,0)+1):INDEX($A$1:$E$30,30,MATCH(G9,$A$1:$E$1,0)+1)*0.9))*1)
and adapt the ranges to your needs. It is entered on the same sheet as the data.
Basically this approach uses ARRAY FORMULA CTRL + SHIFT + ENTER
INDEX($A$1:$E$30,2,MATCH(G9,$A$1:$E$1,0)):INDEX($A$1:$E$30,30,MATCH(G9,$A$1:$E$1,0)))
to get the needed ranges. MATCH looks for the right column. the row number can be set as needed, here its is from 2 to30 adapted to your provided data. My search term in this case is in G9 with Allen as content. The result of the formula is $B$2:$B$30. A +1 after Match gives the other range $C$2:$C$30. Both ranges can then be evaluated with the needed conditions
Pull it down and provide Torres in G10. Then the ranges will be adapted to $D$2:$D$30 and $E$2:$E$30.

Transpose multiple occurrences

EDIT: I have revived the source data source to remove the ambiguity of my last screen shots
I am trying to transpose spreadsheet data where there are many rows where the customer name may be duplicated but each row contains a different product.
For instance
revised original data source
to
revised proposed data format
I would like to do it with formulae if possible as I struggle with VB
Thank you for any help
I realise this is a huge answer, apologies but I wanted to be clear. If you need anything from me, drop me a comment and I'll help out.
Here's the output from my formula:
EDITED ANSWER - Named ranges used for ease of understanding:
These are just an example of a few of the named ranges I have used, you can reference the ranges directly or name them yourself (simplest way is to highlight the data then put the name in the drop down next to the formula bar [top left])
Be wary that as we will be using Array formulas for AccNum and AccType, you will not want to select the entire column and instead opt for either the exact data length or overshoot it by 100 or so. Large array formulas tend to slow down calculation and will calculate every cell individually regardless of it being empty.
First formula
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Account Number ",LEFT((COLUMN(A:A)+1)/2,1)),"")
This formula is identical to the one in the original answer apart form the adjusted heading title.
=IF(Condition,True,False) - There are so many uses for the IF logic, it is the best formula in Excel in my opinion. I have used to IF with COUNTIF to check whether there is more than 0 cells that are more than BLANK (or ""). This is just a trick around using ISBLANK() or other blank identifiers that get confused when formula is present.
If the result is TRUE, I use CONCATENATE(Text1,Text2,etc.) to build a text string for the column header. ROW(1:1) or COLUMN(A:A) is commonly used to initiate an automatically increasing integer for formulas to use based on whether the count increase is required horizontally or vertically. I add 1 to this increasing integer and divide it by 2 so that the increase for each column is 0.5 (1 > 1.5 > 2 > 2.5) I then use LEFT formula to just take the first digit to the left of this decimal answer so the number increases only once every 2 columns.
If the result is FALSE then leave the cell blank ,""). Standard stuff here, no explanation needed.
Second Formula
=CONCATENATE(INDEX(Forename,MATCH(Sheet4!$A2,Reference,0)))
=CONCATENATE(INDEX(Surname,MATCH(Sheet4!$A2,Reference,0)))
CONCATENATE has only been used here to force blank cells to remain blank when pulled by INDEX. INDEX will read blank cells as values and therefore 0's whereas CONCATENATE will read them as text and therefore "".
INDEX(Range,Row,Column): This is a lookup formula that is much more advanced than VLOOKUP or HLOOKUP and not limited in the way that they are.
The range i have used is the expected output range - Forename or Surname
The row is then calculated using MATCH(Criteria,Range,Match Type). Match will look through a range and return the position as an integer where a match occurs. For this I have set the criteria to the unique reference number in column A for that row, the range to the named range Reference and the match type as 0 (1 Less than, 0 Exact Match, -1 Greater than).
I did not define a column number for INDEX as it defaults to the first column and I am only giving it one column of data to output from anyway.
Third Formula
Remember these need to be entered as an array (when in the formula bar hit Ctrl+Shift+Enter)
=IFERROR(INDEX(AccNum,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0))),"")
=IFERROR(INDEX(AccType,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))),"")
As you can see, one of these is used for AccNum and the other for AccType.
IFERROR(Value): The reason that this has been used is that we are not expecting the formula to always return something. When the formula cannot return something or SMALL has run out of matches to go through then an error will occur (usually #VALUE or #NUM!) so i use ,"") to force a blank result instead (again standard stuff).
I have already explained the INDEX formula above so let's just dive in to how I have worked out the rows that match what we are looking for:
SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))
The IF statement here is fairly self explanatory but as we have used it as an array formula, it will perform =Sheet4!$A2 which is the unique reference on every cell in the named range Reference individually. In your mock data this returns a result of: {FALSE;TRUE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE} for the first entry (I included titles in the range, hence the initial FALSE). IF will do my row calculation* for every true but leave the FALSEs as they are.
This leaves a result of {FALSE;2;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE} that SMALL(array,k) will use. SMALL will only work on numeric values and will display the 'k'th result. Again the column trick has been used but to cover more ground, I used another method: ROUNDDOWN(Number,digits) as opposed to using LEFT() Digits here means decimal places so I used 0 to round down to a whole integer for the same result. As this copies across the columns like so: 1, 1, 2, 2, 3, 3, SMALL will alternatively (as the formulas alternate) grab the 1st smallest AccNum then the 1st Smallest AccType before grabbing the 2nd AccNum and Acctype and so forth.
*(Row number of the match minus the first row number of the range then plus 1, again fairly common as a foolproof way to always get the correct row regardless of where the data starts; actually as your data starts on row 1 we could just do ROW(Reference) but I left it as is incase you had data in a different format)
ORIGINAL ANSWER - Same logic as above
Here's your solution in 3 parts
Part 1 being a trick for the auto completion of the titles so that they will hide when not used (in case you will just copay and paste values the whole lot to speed up use again).
=IF(COUNTIF(C2:C11,">""")>0,CONCATENATE("Product ",LEFT((COLUMN(A:A)+1)/2,1)),"") in C
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Prod code ",LEFT((COLUMN(B:B)+1)/2,1)),"") in D
Highlight both of the cells and drag across to stagger the outputs "Product " and "Prod code "
Part 2 would be inputting the unique IDs to the new sheet, I would suggest copying your entire column A across to a new sheet and using DATA > REMOVE DUPLICATES > Continue with current selection to trim out the multiple occurrences of unique IDs.
In column B use =INDEX(Sheet2!$B$1:$B$7,MATCH(Sheet4!$A2,Sheet2!$A$1:$A$7,0)) to get the names pulled across.
Part 3, the INDEX
Once again, we are doing a staggered input here before copying the formula across the page to cover the entirety of the data.
=IFERROR(INDEX(Sheet2!$C$1:$D$11,SMALL(IF(Sheet2!$A$1:$A$11=Sheet4!$A2,ROW(Sheet2!$A$1:$A$11)-ROW(INDEX(Sheet2!$A$1:$A$11,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0)),1),"") in C
=IFERROR(INDEX(Sheet2!$C$1:$D$11,SMALL(IF(Sheet2!$A$1:$A$11=Sheet4!$A2,ROW(Sheet2!$A$1:$A$11)-ROW(INDEX(Sheet2!$A$1:$A$11,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0)),2),"") in D
The formulas of Part 3 will need to be entered as an array (when in the formula bar hit Ctrl+Shift+Enter) . This will need to be done before copying the formulas across.
These formulas can now be dragged / copied in all directions and will feed off of the unique ID in column A.
My Answer is already rather long so I haven't gone on to break the formula down. If you have any trouble understanding how this works, let me know and I will be happy to write up a quick guide, breaking it down chunk by chunk for you.

Concatenate values based on criteria

I have a two column list of data in Excel. The first column being a question number from a test and the second column being a number referencing what is being tested on that question. Some elements are tested on more than one question. What I want to be able to do is to list the question numbers that each element is tested on. For example:
A B Should return: C D
1 Q Ref Q Ref
2 1 N1 1,3,5 N1
3 2 N4 2 N4
4 3 N1 4 N3
5 4 N3
6 5 N1
I want this to be returned using a formula.
Problems I have are returning then concatenating an unspecified number of values from one column that reference to a particular criterion for another column that is further to the right.
EDIT: Looking for a formula answer, not VBA if possible
EDIT: Thanks all for your comments so far. I will have a look at each of the possible solutions given so far and let you know what I go with. The 1,2,3 etc will need to be in the same cell.
Just to put my comment in an answer, so it make more sense.
First sort columns A and B on Column B.
In C2 put the formula:
=IF(B2=B3,A2&","&C3,A2)
Then copy down.
Then in Column E place your unique reference list. And in D2 put:
=VLOOKUP(E2,$B$2:$C$6,2,FALSE)
And copy down.
You can then hide column C.
It does require that it be sorted correctly and a helper column but it does stay to the formulas only rule.
By nature, Excel discourages this in worksheet formulas. I guess they figure that if you do this in a User Defined Function (aka UDF) and it hoops a workbook, it is your own fault and so be it. To that end, I've never seen a standard or array formula using only native worksheet functions that accomplishes this on a 'ragged-edge' array of cells and it's been tried a few times. Consider it #REF! by design.
You can run successive IF functions (up to 64 by xl2007+ standards) to accomplish the string stitching (see this) but you will also be limited to the total length of a formula (see this). We also used 'helper' cells to run off the first 7 IFs in <=xl2003 then reference that cell in the first IF of another 7 nested IFs (rinse and repeat).
TLDR; In short, VBA is your most viable solution (see this). Conditional string concatenation is fraught with problems by itself let alone in an array loop.
CONCATENATE function

Excel formula to extract multiple matching values [duplicate]

This question already has an answer here:
INDEX and SMALL only returning one result
(1 answer)
Closed 7 years ago.
I'm looking for what I thought would be a pretty straightforward formula to compile a list of names based on a criterion. For example, I would have a list of 50 employee names in column A and then a "Y" or "N" next to each name in column B. I would then like to have another tab on the spreadsheet list the names of everyone with a "Y" value in column B. I dont want empty rows between the names in the list on the new tab (this is why I haven't had success with IF statements). I also would like to avoid manually filtering out blank rows.
Lets say your first sheet is Sheet1
on Sheet 2 on a1 enter:
=IF(ISERROR(INDEX(Sheet1!A:A,MATCH("Y",Sheet1!B:B,0))),"",INDEX(Sheet1!A:A,MATCH("Y",Sheet1!B:B,0)))
On a2 enter:
=IF(ISERROR(INDEX(INDIRECT("Sheet1!A"&MATCH(A1,Sheet1!A:A,0)+1&":A50"),MATCH("Y",INDIRECT("Sheet1!B"&MATCH(A1,Sheet1!A:A,0)+1&":B50"),0))),"",(INDEX(INDIRECT("Sheet1!A"&MATCH(A1,Sheet1!A:A,0)+1&":A50"),MATCH("Y",INDIRECT("Sheet1!B"&MATCH(A1,Sheet1!A:A,0)+1&":B50"),0))))
And just drag the 2nd formula down.
Note that I assumed your first sheet is with 50 Rows as you wrote, Otherwise additional modifications needs to be made.
The formula you are looking for is quite complicated and requires cyclic calculation. For this reason, it is not advisable to use for long lists of several hundred or thousand 'names' but a list of 50 names should pose no discernible difficulties.
With the names in Sheet1's A2:A51, use this formula in the worksheet destined to receive the Y names.
=IFERROR(INDEX(Sheet1!$A$2:$A$51, AGGREGATE(15, 6, ROW($1:$50)/(Sheet1!$B$2:$B$51="Y"), ROW(1:1))), "")
Fill down as necessary. Note that the AGGREGATE¹ function is returning the position within A2:A51 with ROW(1:50).
Retrieving the non Y names should be a simple matter of changing the primary condition to (Sheet1!$B$2:$B$51="N") or (Sheet1!$B$2:$B$51<>"Y").
For pre XL2010 circumstances, this standard formula performs the same filtered retrieval.
=IFERROR(INDEX(Z!$A$2:$A$51, SMALL(INDEX(ROW($1:$50)+(Z!$B$2:$B$51<>"Y")*1E+99, , ), ROW(1:1))), "")
¹ The AGGREGATE function was introduced with Excel 2010. It is not available in earlier versions.

Resources