I am using excel to create data sets that are used in a vba application later. I am using this formula:
=INDEX(BaseData!$L$2:$L$10000;MATCH(DataSet!D5&DataSet!E5&DataSet!K5;INDEX(BaseData!$B$2:$B$10000&BaseData!$C$2:$C$10000&BaseData!$D$2:$D$10000;0);0))
usually with a range from f.ex.: A2 - A10000, because my data can be differently long and often vary in data selection.
However, this slows my excel extremely down. I switched to manual calculations, but then, when activating automatic again, my excel instance takes extremely long and often crashes.
I also tried to past some data, but when creating a new dataset, I have to pull the formula down again and sometimes through this errors occur in my data set.
Any suggestions what I can do to make the INDEX-MATCH formulas more performant?
I appreciate your replies!
UPDATE
I guess a lot of performance goes away because index-match does not select the exact range, but also counts in blank rows. How to get the exactl range with index match automatically?
As I mention in my comment above, as long as this is a 'regular' formula and not an Array Formula, you may find success simply replacing "A1:A10000" with "A:A". However barring that, you can create a cell which will calculate reference the number of rows of data which you have, and then use that cell to indirectly reference the complete column with data in it.
CALCULATING YOUR DESIRED RANGE
For the following example to work, I assume that: Column A includes an index key in the form of numbers only; Column A includes no numbers in the header and above; and that the index rows are continuous, with no breaks. Start with the following formula:
=COUNT(A:A)
If my assumptions above hold, then this will return the number of data elements in your table. Once we know where this data starts, we can use this COUNT to determine where it ends. Assume your header is in row 2. (I like to include the header so that if you insert a row beneath the header, Excel picks up that you want to include the new row in your formulas).With that in mind, this formula will create the Excel-style reference which finds the last cell in column A which has data in it:
=ADDRESS(ROW(A2)+1+COUNT(A:A),COLUMN(A2),1,1)
Assuming 50 rows of data [which start at row 3, below the header], and all other assumptions above, this formula will return the text result "$A$53".
If you wanted to do the same thing, but instead return the full range in Column A where data exists (from the header to row 53), you could do as follows:
=ADDRESS(ROW(A2),COLUMN(A2),1,1)&":"&ADDRESS(ROW(A2)+1+COUNT(A:A),COLUMN(A2),1,1)
This returns the text string result "$A$2:$A$53", which is a reference to the full index of unique ID values. It will automatically move around as you would generally expect if you insert any rows or columns. Now assume for your INDEX that you want to pull the same data, but for column B, instead. The formula will be exactly the same, except that where I have "COLUMN(A2)" above, replace with "COLUMN(B2)".
REFERENCING YOUR CALCULATED RANGE
So now you have the address of your proper, limited columns - but how do you actually reference those areas in a formula? By using the INDIRECT function. INDIRECT says "Evaluate some specific criteria. It will create a cell reference. Now look at that cell reference." In its simplest form, this could look like this:
=INDIRECT(A1)
Assume that A1 holds the value "B5". Indirect will pick up the value "B5", and instead of displaying "B5", it will go to B5, and pick up the value there. So to use this with the above, wrap the whole thing in the INDIRECT function. Instead of picking up the text string "$A$1:$A$53", it will actually now reference that range properly. Like so:
=INDIRECT(ADDRESS(ROW(A2),COLUMN(A2),1,1)&":"&ADDRESS(ROW(A2)+1+COUNT(A:A),COLUMN(A2),1,1))
USING A NAMED RANGE
But that is a very long formula to have, and you won't want to use it within a specific cell for a simple INDEX/MATCH. Instead of entering these formulas in cells (although you could), I recommend you go to the Formula Ribbon -> Name Manager -> New Name. Call the name for the index of A "ID_COLUMN". Call the name for the index of "B_COLUMN" (or something more specific).
FINAL FORMULA
Now, if you wanted to make an INDEX/MATCH of your table, which automatically grows/shrinks as you change the data, your formula would look like this [this would, for example, pick the row from column B where column A has the number 100]:
=INDEX(ID_COLUMN,MATCH(100, B_COLUMN, 0))
Related
I'm trying to create a dashboard, where upon selecting a company from a dropdown list, it will list all of the company's bankers where the data is on another worksheet tab.
So far, the Index Match formula seems to be running fine, however, it keeps on running and lists the bankers from other companies. How can I fix this?
File can be downloaded here: https://drive.google.com/file/d/1fw7yh4AEF1vx3cuG6E_1RBTrTD_k74KD/view?usp=sharing
You can try below approach by pasting below formula in cell E5:
=IFERROR(INDEX(RAW!$D$2:$D$279,SMALL(IF(RAW!$B$2:$B$279=$C$5,ROW(RAW!$D$2:$D$279)-1,10^10),ROWS($A$1:A1))),"")
This is array formula so it needs to be committed by CTRL+SHIFT+ENTER and then copy it down as much needed.
Explanation:
INDEX is retrieves the range reference from the defined GRID based on the row and column reference.
In this particular case, we intend to extract the references sequentially. This is performed by SMALL(IF(RAW!$B$2:$B$279=$C$5,ROW(RAW!$D$2:$D$279)-1,10^10),ROWS($A$1:A1))
Within this formula, first portion is the ARRAY building IF formula as below
IF(RAW!$B$2:$B$279=$C$5,ROW(RAW!$D$2:$D$279)-1,10^10) which tests cells in column B if they match criterion value. If the value matches then ROW reference is returned and if it doesn't then it returns a very large value i.e. 10^10. We subtract 1 from row reference as the data starts from row 2 so it should be (n-1) in principle. This arrangement produces an ARRAY like {1;2;3;4;5;6;7;10000000000....} for value "Acorda".
But we need to pass one element at a time to INDEX formula so this is done by SMALL(IfBasedArray,k) where k part is serially generated by ROWS($A$1:A1) which starts with 1 and increments downwards as the formula gets copied which thus enables INDEX to return desired results.
Finally, when the matches are finished then big number i.e. 10000000000 gets fed and generates an error which then is covered by IFERROR formula to return blank!
Please apply this formula to your sheet's E5 and copy down. Note that I created the named range Coms which refers to RAW!B2:B279.
=IFERROR(IF(INDEX(Coms,MATCH($C$5,Coms,0)+ROW()-ROW(E$5))=$C$5,INDEX(Coms,MATCH($C$5,Coms,0)+ROW()-ROW(E$5)),""),"")
If you prefer, the name in the formula can be replaced with the address, as you had it originally, or you define the named range to expand dynamically.
A simpler option than the 2 previous answers (doesn't require an CSE array entered formula or multiple nested INDEX/MATCHES) would be to have a couple of 'helper' cells in say G5/G6
Start Row would be =MATCH(C5,RAW!B:B,0) This finds the first row on your RAW sheet where the selected company appears
Advisor Count would be =COUNTIFS(RAW!B:B,C5) counts how many rows there are for this particular company
Then your formula in cell E5 becomes =IF(D5<=$G$6,INDEX(RAW!$D:$D,$G$5+D5-1),"") which you can drag down.
screenshot showing formulas/result
I am making a spreadsheet which has multiple sheets and one of the sheets has an equation that looks to see if there is anything written in a certain cell on all the other sheets. Right now I just use this equation to find out whether or not it has anything written in that cell.
=IF(LEN('A'!N18)>1,CONCATENATE('A'!C18," "),)
This is just checking to see if anything is in the cell. The problem is that I want this to keep working if I add a new row on A, but right now it bumps row 18 to 19 and I am left with no row 18 so it won't even check that new row!
If you want to add a row between row 1 and row 18 on worksheet A but keep your formula references to A!N18 and A!C18 then you need to use INDIRECT or INDEX. Of these two, INDEX is the better choice as it is not volatile. A volatile function like INDIRECT will recalculate whenever anything in the workbook chanmges. A non-volatile function like INDEX will only recalculate when something that affects its outcome is changed.
'INDIRECT method; works but not optimal
=IF(LEN(INDIRECT("'A'!N18"))>1,CONCATENATE(INDIRECT("'A'!C18"," "),)
'INDEX method; works and is non-volatile
=IF(LEN(INDEX('A'!N:N, 18))>1,CONCATENATE(INDEX('A'!C:C, 18)," "),)
The link that Slai posted in the comments to your question should be what you're looking for. If you don't want a reference to change when you add/delete rows/columns you need to use absolute references. As currently written "N18" and "C18" are relative references. If you change the columns/rows on sheet 'A', these references will automatically change with them. That's why it's moving to row 19 on you.
You can turn these into absolute references by adding "$" like this: "$C$18" and "$N$18". The first "$" sets the absolute reference for the column and the second sets the absolute reference for the row. You can mix and match these for various results.
Mixing relative and absolute values really comes in handy when you are reusing a formula with slight differences. For instance, if you want to multiply a number in column b (starting with row 4) by the number in A1 and show the result in column C (also starting with row 4). You'll always be using A1 so we can set this as an absolute value and in C4 enter the formula =$A$1*B4. Copy this down column C and it will automatically update the B value to the new column but will always use "$A$1" for the other part.
You can split the relative reference by only using the "$" on the column or row reference of the reference. Whichever one you use it on will be locked and the other can still adjust based on changes to the sheet or copying. Learning how to use absolute references can be a great time-saver.
I'm curious about part of your formula though. Why are you concatenating C18 with just a blank space? If you are using the info somewhere else, it may make sense to add the space in that concatenate but it's a personal choice.
I'm going around in circles with this and have tried as many different options as I can think of - VLOOKUP, INDEX/MATCH, IF etc... but I'm failing everytime.
I need to create a drop down list in sheet 3 (column A) that gets populated with values in column B of sheet 2, only where the value in column G of sheet 2 is "Yes". The values in sheet 2 look as follows:
This is what is shown at present:
I am using the following formula within Name Manager to get to this point:
=OFFSET(Units!$B$11,0,0,COUNTIF(Units!$B$11:$B$202,">"""),1)
and although this works, it's not quite as I need it to be. I've tried using Index/Match, small, VLOOKUP etc... but Excel reports that either I've too few arguments or can't reference a worksheet.
I've literally been though as many excel websites as I can find but no one seems to cover creating drop down lists where the drop down is dependent on a specific selection.
The values within sheet 2, column B are obtained from a hidden sheet and collected using the following query:
=IF(ISERROR(INDEX(All_Units!$D$2:$D$660542,MATCH(Units!A11,All_Units!$C$2:$C$660540,0))),"",INDEX(All_Units!$D$2:$D$660542,MATCH(Units!A11,All_Units!$C$2:$C$660540,0)))
I wondered whether I could take this query and use it to generate the drop down list, something along the lines of:
=INDEX(Units!$B$11:$B$202,MATCH(Units!$G$11:$G$202="Yes",Units!$G$11:$G$202,0)))
but this returns an error. The closest I got was using the OFFSET formula above but performing a COUNTIF, however; this unsurprisingly wouldn't tie Column B to the corresponding 'Yes' in column G.
Does anyone have any ideas as to how I can get this working?
You will need to create another sheet into which you will place an array formula. This formula will return all the desired output.
so create a sheet and name it something like DataVal
In A2 put the following array formula:
=IFERROR(INDEX(Units!$B$11:$B$202,MATCH(1,(Units!$G$11:$G$202="Yes")*(COUNTIF($A$1:A1,Units!$B$11:$B$202)=0),0)),"")
Being an array formula it needs to be confirmed with Ctrl-Shift-Enter. If done correctly then Excel will put {} around the formula.
Then copy/drag down far enough to ensure capturing every possible return.
Then use another INDEX/MATCH to create the named range (OFFSET() is volatile and should be avoided when possible). The formula would be something like:
=DataVal!$A$2:INDEX(DataVal!$A:$A,MATCH("ZZZ",DataVal$A:$A))
This will dynamically set the named range to the extent of the dynamic list created by the array formula above.
I used this VLookup formula to retrieve value from another sheet Sheet2 which contains a table with two columns NumEchelon, Indice:
=RECHERCHEV("1/1";Sheet2[NumEchelon];Sheet2[Indice];faux)
But it doesn't return any value, when i click on the cell i found just the formula not the value i want to retrieve from the sheet Sheet2.
Looks like you are using french version of Excel, so I will leave it up to you to find the translated commands. The basic problem from what I am gathering is you are looking up "1/1" in the named range NumEchelon. I am going to guess that this named range is 1 column wide. sheet2[Indice] is a separate chunk of data.
Vloopkup is supposed to search for a specified term in a table (usually 2 or more columns wide located to the right of the search column) and return a value in the same row as the found value in a specified column. The columns are numbered left to right with the first column being zero. The false or FAUX at the end tells it you want an exact match.
So without seeing your data I would say make sure that NumEchelon covers both columns of information, and INDICE column is to the right of NumEchelon. Where you have Sheet2 Indice replace with with a numeric value for the column its from the table you made for the vlookup.
So Assuming NumEchelon is A1:A8 and Indice is B1:B8 I would do the following:
Use a new named range "MonTableaux" and define it as sheet2!A1:B8
=VLOOKUP("1/1",MonTableaux,2,0)
Without the named range it would look like
=VLOOKUP("1/1",sheet2!$A$1:$B$8,2,0)
'note the 0 is the same as false
Now you may be using TABLES and I am not all that familiar with table so there may be short cuts. If that is the case someone point it out to me and I will delete my answer.
If your information you want to return in not lined up vertically with the information you are searching for or if the information you want to return is located to the left of what you are searching for you will want to use a combination of INDEX and MATCH. maybe something like this:
=INDEX(sheet2[Indice],match("1/1",sheet2[NumEchelon],0))
If the formula is showing up in the cell, and not a result like #N/A then the cell is likely formatted as Text, change it to General and click in the formula bar and hit enter again to show the formula result instead of the formula text.
What I'm wanting to do is have a formula in one cell that counts the values in a range that conform to a lookup of that range cell's value compared to another cell.
OMG, now that I look at it, that is totally confusing. Let me try to clarify a lot here.
Say we have Cell1, which will hold the counting formula. I have a list of values in a two-column table, Table1. The range, Range1 that Cell1 will be counting from is a range of cells that have List Validation in them. Table1 holds references to all values that can result from those Lists, in column 1. I have another cell, Cell2, which holds a number value. Column 2 of Table1 holds values that reference Cell2. I need to count the number of values from Range1 whose row matches in Table12 match the value in Cell2. Is there a way I can do this with COUNTIF without referencing each cell individually? Is there some shorthand (like Range.currentValue) that I can use to get the value of the cell currently being checked? The range is 11 rows long, and I need to do a second range that has 12 rows counted.
Man, I really don't know how to clarify that any more... I'll post this for now, in case anyone can understand what I'm saying and knows the answer, while I work on a sample spreadsheet I can upload.
I did my best to visually represent what I'm trying to accomplish:
http://gyazo.com/b83295baf3b156683a5c39b40c806504
Extended explanation: http://gyazo.com/4048802050e3dcfca7aee238acc2f7dd
Use a helper column, say, between the brown and the first blue or at the right of the setup. Use a vlookup like
=vlookup(brownvalue,BluetableRange,2,false)
Then do a countif on the helper column
=countif(HelperColumn,"<="&GreenCellAddress)
You can hide the column with the helper if it upsets your spreadsheet design.
You can (and probably should) use a helper column as Teylyn suggests. But, for when that may be inconvenient, you can also use an array formula:
=SUM(COUNTIFS(listlookupcolumn,rangeoflists,numbervaluecolumn,"<="&numbertomatch))
To enter it as an array formula, type "ctrl-shift-enter" after editing the formula, rather than just "enter"
Rough explanation: since rangeoflists is in a place where a single value is expected, the countifs is calculated once for each value, and the array of results is passed to sum. Use the "evaluate formula" feature to see the intermediate result array.
Afterthought: It occurs to me now that this does rely on listlookupcolumn containing unique values. (Almost certainly true in this example.) You can modify the formula a bit to get around this:
=SUM(SIGN(COUNTIFS(listlookupcolumn,rangeoflists,numbervaluecolumn,"<="&numbertomatch)))
The SIGN function will keep you from double counting.
Again, you must use "ctrl-shift-enter" for this to work. (Yes, as I'm sure others are ready to point out, you can also use the sumproduct hack in this instance.)