Related
I want to get the count of cells used in an excel function.
For example say I have a sum function ='CV'!D11+Farmer!D11+'County'!D11+Rt!D11+WT!D11+'Country'!D11
I need a function that will tell me how many cells were used to get the total sum. In this case it is 6. The tricky part is if one of the cells used is blank I do not want it counted. For instance say cell D11 on the Farmer sheet is blank I do not want it counted in the total. So the total should be 5.
Use COUNT:
=COUNT('CV'!D11,Farmer!D11,'County'!D11,Rt!D11,WT!D11,'Country'!D11)
It will only count the cell if it has a number
You should really try to collate all your data in to a single sheet before running calculations. For the sake of example, I'll assume you have it in the range A1:A5, then you can add handling of the various cases using array formulas:
Get the count of non-empty cells (the ISBLANK function is untrustworthy in my experience): {SUM(IF(LEN(A1:A5)>0,1,0))}
Get the sum of those cells: SUM(A1:A5)
(must use Ctrl+Shift+Enter to enter the formula as an array formula, you will know it worked if the formula shows like {IF(...)} with the curly brackets)
Because blank/missing values are treated implicitly as 0 in the SUM function, this case is simple. If you have other validations then you'd have to write an array formula for the summation as well. For example, only including numbers between a min and max threshold (e.g. if you want to exclude outliers):
{SUM(IF(AND(A1:A5 >= yourMinValue, A1:A5 < yourMaxValue), A1:A5, 0)}.
If I understand your question correctly, you want to literately count the number of cells used in a formula which in your example is summing 6 values from 6 different locations.
I used the following example to demonstrate my solution:
The sum of =A1+B1+C1+D1+E1+F1 is 10 where cell C1 has a 0 value in it but cell E1 is blank.
Using the following array formula I was able to count the number of cells that have a value other than 0:
=SUMPRODUCT(IFERROR(ABS(N(INDIRECT(TRIM(MID(SUBSTITUTE(RIGHT(FORMULATEXT(A3),LEN(FORMULATEXT(A3))-1),"+",REPT(" ",100)),100*ROW(INDIRECT("1:"&LEN(FORMULATEXT(A3))))-99,100)))))>0,0)*1)
Please note you MUST press Ctrl+Shift+Enter upon finishing the formula in the formula bar otherwise they will not function correctly.
The logic is to use a combination of TRIM+MID+SUBSTITUTE+RIGHT+FORMULATEXT+REPT+ROW+INDIRECT to extract the cell addresses from the original formula, then use INDIRECT to convert the cell address into the values stored in those cells, then use a combination of IFERROR+ABS+N to find out if any of these values are not 0, and lastly use SUMPRODUCT to add up all the TRUE results.
It is obvious that there are a couple limitations of my solution:
If your actual formula is not strictly in the form of A+B+C+D+E+F, then my SUBSTITUTE part of formula will need further modification;
The formula will treat cells containing 0 as blank and does not include them in the count.
Let me know if you have any questions. Cheers :)
I want to count number of values (N/D) in the array (below:table: list) for criteria 1 is date range( from date and through Date) and criteria 2 is Shift A, b acros ( as shown in below table-output). I want to fill column D/N with how many times D/N occur for a date range and shift A,B,C,D?
output
From Date Through Date Shift D/N
25-May-19 26-May-19 A ?
25-May-19 26-May-19 B ?
Table- list
Dates A B C D
25-May-19 N D - -
26-May-19 N D - -
27-May-19 - D N -
INDEX(A:E,MATCH(H7:I7,A:E,0),MATCH(J7,A:E,0))
Value -?
Part of the problem you may be having is dates. Make sure your dates are excel dates and not string/text that looks like a date. Simply changing the formatting of a cell does not make it a date, it simply tells excel how to try and display the information in a cell.
Dates in excel are stored as integers and they represent the days since 1900/1/1 with that date being day 1. One of the easiest ways to test if a cell contains a date or a string is:
=ISTEXT(A1)
or
=ISNUMBER(A1)
Where A1 is the cell with the date to be tested.
If it returns TRUE for the first formula it is a string/text. FALSE means it is a number. The opposite TRUE and FALSE results apply for the second formula.
In your formula's when you have something between quotes "", it will be interpreted as a string. SO something like "<=19/05/26" mean its looking for a string less than that, not a date less than that. For doing a date comparison, either concatenate the text comparison with with a cell containing a date to compare to "<="&B2 where B2 has the date or if you want to hard code it use something like "<="&Date(19,05,26)
In order to make the following solution work, your dates all need to be stored as a number. AKA Excel serial date format.
Based on the data being layed out as per the image below, you can use COUNTIFS, INDEX, and MATCH to get the date your are looking for. I recommend find your count of D and N separately and adding them together after for a total. However if you want it in a single cell formula solution it can be achieved as well as demonstrated by the results in column N. however the formula starts to get long and can be difficult potentially read/maintain at a later date.
The core of the solution will be the COUNTIFS functions. The format of the COUNTIFS function is as follows:
COUNTIFS(Range to count 1, Criteria 1, Range to count 2, Criteria 2,...,Range to count n, Criteria n)
Let start building your formula one criteria at a time. The first Criteria will be all dates that are greater than or equal to the from date. If you only want the dates after the from date, drop the equal sign or the criteria.
=COUNTIFS($A$2:$A$4,">="&$G2,
Note the $ to lock the cell references. This is done so that when the formula gets copied, the column or row references beside the $ does not change.
Then second criteria is similar to the first except you want to grab all the dates less than or equal to the through date. Again include/drop the equal sign to suit your needs.
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,
The next criteria will be to get all the cells that match D or N the column header. Lets just focus on D for now. The tricky part is to define which column to look in. For now lets call the column to look in XXX which will make the formula become:
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,XXX,J$1)
OR
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,XXX,"="&J$1)
NOTE: both formulas are the same. When no comparison operator is provided
it is taken as "=" by default.
Now in order to define XXX, INDEX and MATCH will be your friends. An important side note about INDEX is that it does not directly return the value of a cell but instead returns a cell address which in turn pulls a cell value. The basic format of INDEX is:
INDEX(Range to look in, Range's ROW to look in, Range's COLUMN to look in)
That is for a 2 dimensional range. If your range is 1 dimensional, either just a column or just a row, then only the second argument "Range's Row..." need to be provided and it represents how far down the list to go.
What gets interesting about a 2D INDEX is that when 0 is provided for ROW to look in or the Column to look in, instead of throwing an error, it instead returns all rows or columns. THIS IS IMPORTANT because you want all rows of just 1 specific column. That mean your INDEX formula is going to start to look like:
INDEX($B$2:$E$4,0,SPECIFIC COLUMN NUMBER)
So now you need to find a specific column number. That is where MATCH will be your friend. MATCH takes the following format:
MATCH(Value to find, 1D range to look in, what type of search)
You already know you are going to try and match your shift column so that will be your look up value, and the range to look in will be your column headers. The type of search you will want in this case is an exact match which is represented by 0. That means your MATCH formula will look like:
MATCH($I2,$B$1:$E$1,0)
Now to combine the various pieces, throw the MATCH formula into your INDEX and replace the "SPECIFIC COLUMN...". Your INDEX will now look like:
INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0))
And the formula above can now replace the XXX in your COUNTIFS formula and you will get:
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0)),J$1)
Place the above formula in J2 and copy the cell down and to the right.
In L2 use one of the two formulas to get the total of D and N in the date range:
=SUM(J2:K2)
OR
=J2+K2
Now to get your formula all in one cell, look at the second formula above. You can simply go to the contents of cell J2 and copy the entire formula. Then edit cell L2 and replace the cell reference for for J2 with the copied formula. Repeat the process by copy formula in K2 and replacing the reference to K2 in L2. You will wind up with a formula that looks like:
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0)),J$1)+COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0)),K$1)
Much longer and harder to read which is why I recommend breaking the formula down into its parts for D and N separately.
Now as an alternate method you could use SUMPRODUCT and get into array operations. Your SUMPRODUCT formula to place in I2 and copy down and right could be:
=SUMPRODUCT(($A$2:$A$4>=$G2)*($A$2:$A$4<=$H2)*(INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0))=J$1))
I am trying to get a sum of G3:G47 if A54 matches the first 3 characters in the cell range A3:A47
This is the formula I have been trying to tinker with, but it doesn't work.
=SUMIF(A$3:A$47,LEFT(A$3:A$47,3)=[#[Sprint ID]],C$3:C$47)
Use WildCards:
=SUMIF(A$3:A$47,[#[Sprint ID]] & "*",C$3:C$47)
I am going crazy over this. It seems so simple yet I can't figure this out. I have two worksheets. First worksheet is my data. Second is like an answer key. Upon checking checking, A1:B1 in Sheet 1 is a match with the conditions in Row 52 in SHEET 2, therefore, the value in Column C is "MGC". What is the formula that will perform this function? It's really hard to explain without the data so I pasted a link of the sample spreadsheet. Thank you so much in advance.
sample spreadsheet here. https://docs.google.com/spreadsheets/d/1_AjuNfCdGfEM-XkqPa6W4hSIxQg4NM2Vg4c2C1pQ_vQ/edit?usp=sharing
screenshot here. (wont let me post i have no reputation)
In Sheet2, insert a column in front of Column A and put the formula in A2 =C2&D2.
Then in Sheet1, Cell C2 the formula =vlookup(A2&B2,Sheet2!A:B,2,0).
the first make a concatenated key to lookup, then the second looks up that key.
How about a index(match())? If I've understood correctly you need to match across both the A and B column in sheet one, checking for the relevant values in B and C on sheet 2 to retrun worksheet 2 column a to worksheet 1 column c.
third version try:
=INDEX(Sheet2!$C$1:$C$360,MATCH(Sheet1!A1&Sheet1!B1,Sheet2!$B$1:$B$360&Sheet2!$C$1:$C$360,0))
Basically what this does is use concatenation, the & operator, to specify you are looking for "Criteria A" & "Criteria B" in sheet 1, which makes the string "Criteria A Criteria B", which is supplied in the first part of the match function.
In the second it then says match this against all of my variables in sheet 2 in the same way with concantenation.
The final part of match function (0) specifies you want an 'exact' match
It then supplied this as a reference to the index function, which then finds the row intersecting with the value you want, and returns that.
As noted here https://support.microsoft.com/en-us/kb/59482 this is an array formula, so it behaves differently, and must be input differently. https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7
There are (at least) 2 ways you could do this without VBA.
USING A SORTED LIST
The first relies on the assumption that your data can be re-sorted, so that everything "Unreported" is in the top, and everything "reported" is together below that (or vice versa). Assuming that this is the case (and it appears to already be sorted like this),we will use the function OFFSET to create a new range which shows only the values that align with either being "Unreported" or "Reported".
Offset takes a given reference to a point on a sheet, and then moves down/up & left/right to see what reference you want to return. Then, it returns a range of cells of a given height, and a given width. Here, we will want to start on Sheet2 at the top left, moving down until we find the term "Unreported" or "Reported". Once that term is found, we will want to move one column to the right (to pull column B from sheet 2), and then have a 'height' of as many rows as there are "unreported" or "reported" cells. This will look as follows in A1 on sheet 1, copied down:
=OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),1)
This says: First, start at cell A1 on sheet2. Then find the term in A1 (either "unreported" or "reported", on sheet2!A:A (we subtract 1 because OFFSET starts at A1 - so if your data starts at A1 we need to actually stay at "0". If you have headers on sheet2, you will not need this -1). Then, move 1 column to the right. Go down the rows for as many times as Sheet2 column A has the term found in Sheet1 A1. Stay 1 column wide. Together, this will leave you with a single range on sheet2, showing column B for the entire length that column A matches your term in sheet1 A1.
Now we need to take that OFFSET, and use it to find out when the term in Sheet1 B1 is matched in Sheet2 column B. This will work as follows:
=MATCH(B1,[FORMULA ABOVE],0)
This shows the number of rows down, starting at the special OFFSET array created above, that the term from B1 is matched in column B from sheet2. To use this information to pull the result from column C on sheet 2, we can use the INDEX function, like so:
=INDEX([FORMULA ABOVE],MATCH(B1,[FORMULA ABOVE],0))
Because this would be fairly convoluted to have in a single cell, we can simplify this by using VLOOKUP, which will only require the OFFSET function to be entered a single time. This will work as follows:
=VLOOKUP(B1,[FORMULA ABOVE],2,0)
This takes the OFFSET formula above, finds the matching term in B1, and moves to the 2nd column to get the value from column C in sheet2. Because we are going to use VLOOKUP, the offset formula above will need to be adjusted to provide 2 columns of data instead of 1. Together, this will look as follows:
FINAL FORMULA FOR SHEET1, C1 & COPIED DOWN
=VLOOKUP(B1,OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),2),2,0)
OPTION USING ARRAY FORMULAS
The above method will only work if your data is sorted so that the REPORTED and UNREPORTED rows are grouped together. If they cannot be sorted, you can use an ARRAY FORMULA, which essentially takes a formula which would normal apply to a single cell, and runs it over an entire range of cells. It returns an array of results, which must be reduced down to a single value. A basic array formula looks like this [assume for this example that A1 = 1, A2 = 2...A5 = 5]:
=IF(A1:A5>3,A1:A5,"")
Confirm this (and all array functions) by pressing CTRL + SHIFT + ENTER, instead of just ENTER. This looks at each cell from A1:A5, and if the value is bigger than 3, it gives the number from that cell - otherwise, it returns "". In this case, the result would be the array {"";"";"";4;5}. To get the single total of 9, wrap that in a SUM function:
=SUM(IF(A1:A5>3,A1:A5,""))
In your case, we will want to use an array formula to see what row in Sheet2 matches A1 from Sheet1, and B1 from Sheet1. This will look like this:
=IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW($B$1:$B$100),""),"")
This checks which rows in column A from sheet 2 match A1. For those that do, it then checks which rows in column B from sheet 2 match B1. For those, it pulls the row number from that match. Everything else returns "". Assuming no duplicates, there should only 1 row number which gets returned. To pull that number from the array of results, wrap the whole thing in a MATCH function. Now that you have the row number, you can use an INDEX function to pull the result in Column C with that row, like this:
FINAL ARRAY FORMULA METHOD
=INDEX($C$1:$C$100,MAX(IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW(Sheet2!$B$1:$B$100),""),"")))
Remember to confirm with CTRL + SHIFT + ENTER instead of just ENTER, when you type this formula. Note that I didn't refer to all of Sheet2!A:A, because array formulas run very slowly over large ranges.
The following formula should work without making any changes to the datasheets.
=INDEX(Sheet2!$A$1:$A$360,MATCH(Sheet1!A1,IF(Sheet2!$C$1:$C$360=Sheet1!B1,Sheet2!$B$1:$B$360),0))
Remember to save this formula as an array with CTRL+SHIFT+ENTER
Documentation on how to use INDEX and MATCH against multiple criteria can be found on Microsoft Support.
It's not clear what you want to do with the multiples that do not have corresponding matches. txed is listed as Unreported twice in Sheet1; kntyctap is listed as Unreported three times. There are only one corresponding match on Sheet2 for each of these.
Non-array Standard Formulas for multiple criteria matches
For Excel 2010 and above use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999,AGGREGATE(15,6,ROW(1:999)/((Sheet2!$B$1:$B$999=A2)*(Sheet2!$C$1:$C$999=B1)), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
For version of Excel prior to 2010 use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999, SMALL(INDEX(ROW($1:$999)+((Sheet2!$B$1:$B$999<>A1)+(Sheet2!$C$1:$C$999<>B1))*1E+99, , ), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
I've handled error with the IFERROR function in that latter formula. Excel 2003 and previous may have to use an IF(ISERROR(..., ...)) combination.
Something I've wanted to do quite a bit lately, and can't work out how to do, is MATCH in a column I pass as an argument. Essentially, I have a two dimensional array, and I want to be able to find the first occurrence of a given value in the nth column, for any given value of n, and return the row number it occurs at. Alternatively (and more-or-less equivalently), I want to be able to search in the column with a given column header. Is there any way to do this?
Effectively, I want to simulate the non-existent function =MATCH(lookup_value,lookup_array,lookup_column,[match_type])
I've kludged together a horrible bodge job using INDIRECT, which works, but offends me horribly.
=MATCH(lookup_value,INDIRECT("R"&<top of array>&"C"&<left of array>+<column reference>&":R"&<bottom of array>&"C"&<left of array>+<column reference>,FALSE),FALSE)
This formula should work for you and will avoid INDIRECT. Anytime you can avoid using Indirect, I recommend doing so.
=MATCH(lookup_value,INDEX(lookup_array,0,MATCH(lookup_header,array_headers,0)),0)
If you aren't looking up the column by column header and just have the column number, then it becomes easier:
=MATCH(lookup_value,INDEX(lookup_array,0,column_number),0)
You could do something like this:
Set findCell = ActiveSheet.Range("A:Z").Find(What:="term_to_search")
Will select a header based on your search term.
Set range = ActiveSheet.Range(findCell, findCell.Offset(DEF_MAX_ROWS, 0))
Set up a range which will search from that header down a whole column.
For column references beyond Z you might switch notation (Excel Options, Formulas, Working with formulas and check R1C1 reference style) and, assuming the value to be looked up is in 'A1' (R1C1) with the column number in 'A2' (R2C1) apply:
=MATCH(R1C1,INDIRECT("C"&R2C1,0),0)
to save some complexity in converting a string of two or three characters into the relevant column number.
Say we have a two dimensional array: B3:E17 and we wish to locate Happiness in the third column of that array.In G1 enter:
B3:E17
In G2 enter:
3
In G3 enter:
=ADDRESS(ROW(INDIRECT(G1)),COLUMN(INDIRECT(G1))+$G$2-1) & ":" & ADDRESS(ROW(INDIRECT(G1))+ROWS(INDIRECT(G1))-1,COLUMN(INDIRECT(G1))+$G$2-1)
This will display the address of that third column. Then in G4 enter:
=MATCH("Happiness",INDIRECT(G3),0)
For example:
You can specify a range in a formula using the INDIRECT function. So, for example, if you put the letter designation for the column you want to search in cell A75, you could use:
=MATCH("Value_To_Match", INDIRECT(A75 & ":" & A75), 0)
So, if the value in A75 is G, the string built up in the INDIRECT call is G:G, and the MATCH will look through column G for "Value_To_Match" and return the row number in which it's found.
Using this idea, you can put a formula into A75 that generates the column designation for the column you want to search. For example, if your column headers are all in row 1, and the header you want to search for is in A74, you can do:
=CHAR(MATCH(A74, 1:1, 0) + 64)
using the CHAR function to convert numbers into ASCII characters, so 65 becomes A, 66 becomes B, etc. Note that this will only work if you don't have columns past Z. You'd need a more fussy formula to do the right thing with AA, etc.
You can overcome the annoyances of dealing with column letters by using R1C1 notation instead, which you can activate by adding a second parameter of FALSE to the INDIRECT expression. Now, instead of specifying your column by a letter, you'll specify it using a number. This simplifies the column-finder in A75:
=MATCH(A74, 1:1, 0)
and also the INDIRECT expression in your overall MATCH:
=MATCH("Value_To_Match", INDIRECT("C" & A75, FALSE), 0)