I have the following data:
Example:
A B C
EmployeeID EmployeeName EmployeeSalary
-------------------------------------------
E101 JAK 20000
E102 SAM 25000
E103 John 20000
E104 Shawn 30000
I have the cell H1 in which i type salary of the employee, and in the below cell that is cell H2, I2, J2 should list the employee details according to the given salary in the cell H1.
I have used VLOOKUP function for this.
For cell H2:
=IFERROR(VLOOKUP(H1,C2:A5,1,FALSE),"EmployeeID not found")
For cell I2:
=IFERROR(VLOOKUP(H1,C2:B4,2,FALSE),"EmployeeName not found")
For cell J2:
=IFERROR(VLOOKUP(H1,C2:C4,3,FALSE),"EmployeeSalary not found")
Note: The above works fine for single result to display but when i enter 20000 it will only show single record NOT all which meet the given criteria.
There are three ways to deal with this:
First the Formula:
I set up the Field as such which will become apparent with another method:
So in J4 I put the following formula:
=IFERROR(AGGREGATE(14,6,$C$2:INDEX(C:C,MATCH(1E+99,C:C))/($C$2:INDEX(C:C,MATCH(1E+99,C:C))=$H$2),ROW(1:1)),"")
In H4 I put:
=IF($J4<>"",INDEX(A$2:INDEX(A:A,MATCH(1E+99,$C:$C)),AGGREGATE(15,6,(ROW($C$2:INDEX($C:$C,MATCH(1E+99,$C:$C)))-1)/($C$2:INDEX($C:$C,MATCH(1E+99,$C:$C))=$J4),COUNTIF($J$4:$J4,$J4))),"")
Which I then drag across to I4. Then drag all three formulas down till you are sure you have covered all the possible results.
This is a non CSE array formula. Array formulas calculations are exponential, so we need to limit the reference range to the minimum needed. All the INDEX($C:$C,MATCH(1E+99,$C:$C)) finds the last cell with data and sets this as the end reference.
The IFERROR() wrapper on the first allows the formula to be copied down further than the list will return and avoid the #N/A. In the picture the formulas occupy the first 8 rows.
Second we use the Advanced Filter:
First we set up the area around H1 like this:
Then we navigate to Advanced Filter which is on the Data tab. This window pops open:
Then we enter the Information:
Mark the Copy to another location.
List Range is $A$1:$C$5
Criteria Range is $A$1:$C$5
Copy to range is $H$3:$J$3
Then hit okay.
The third is vba which mimic the Advanced Filter:
Sub atfilt()
Dim ws As Worksheet
Dim rng As Range
Dim critrng As Range
Dim cpytorng As Range
Dim lstrow As Long
Set ws = Sheets("Sheet9")
lstrow = ws.Range("A" & ws.Rows.Count).End(xlUp).row
Set rng = ws.Range("A1:C" & lstrow)
Set critrng = ws.Range("H1:H2")
Set cpytorng = ws.Range("H3:J3")
rng.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=critrng, CopyToRange:=cpytorng, Unique:=False
End Sub
Each has their disadvantages:
Formula: If the data set is large then(1,000 rows or more) the calculations will be long.
Advanced Filter: Each step must be redone each time a new filter is wanted. It is not automatic.
VBA: It is VBA and requires a certain understanding on how to use it.
I agree with #Scott Craner's comment that autofilter would be great here to allow you to find multiple values based on a criteria. Unfortunately (maybe someone can fill this bit in :)) I don't know much about autofilter in vba for this purpose (only used it once or twice)
I can tell you about left lookups with INDEX(MATCH()) which should work in place of your VLOOKUPS.
Format:
INDEX("column of values to return",MATCH("lookup value","column to find lookup value", 0))
so in your example for cell H2 you could use:
=IFERROR(INDEX($A:$A,MATCH(H1,$C:$C,0)),"EmployeeID not found")
Note the "0" in the formula is to find an exact match!
Related
Excel has been out of my scope for a long time, and this feels very simple. Looking for the formula to filter a list, but the results are on a new tab.
Closest thing I have found is this FILTER function, but as the site reads it's a new feature to be released in 2019. So I do not have access to it because I'm using Excel 2013.
I'm trying to filter on a field of Date Ranges, so all entries in the current week would be filtered to the new tab.
So filter with dates for the week of 06 Oct 2019 to 12 Oct 2019 on a new tab would return the top 2 rows only.
I have tried the FILTER function, No it doesn't work in MS Excel 2013. I also reviewed VLOOKUP, nope. I know PIVOT is not what i want. I want to avoid VBA scripting because this will go to a non-developer eventually.
Lastly filter the current table will not meet my objective.
The Advanced Filter will only copy to the same worksheet.
For a formula, you can create an array of relevant row numbers and return them, in order, using the AGGREGATE function using the Small function and the option to ignore errors.
Then use this to INDEX into the array, and IFERROR to take care of dragging the formula down more rows than are present.
For example, using Tables and structured references: In the upper right cell of where you want the results:
=IFERROR(INDEX(Table1_2,AGGREGATE(15,6,1/((Table1_2[[Dates]:[Dates]]>=From)*(Table1_2[[Dates]:[Dates]]<=To))*ROW(Table1_2)-ROW(Table1_2[#Headers]),ROWS($1:1)),COLUMNS($A:A)),"")
Fill right and down to fill your matrix and the references should self-adjust.
Change the Table to whatever your table is named, or use absolute addressing.
Multiple roads to Rome here, but let's assume this sample data on Sheet1:
Formulas (just an example)
This is my result on Sheet2:
Formula in A2:
=IFERROR(INDEX(Sheet1!A$1:A$10,SMALL(IF((Sheet1!$A$2:$A$10>=TODAY()-WEEKDAY(TODAY(),2)+1)*(Sheet1!$A$2:$A$10<=TODAY()-WEEKDAY(TODAY())+7)=1,ROW(Sheet1!$A$2:$A$10),""),ROW(A1))),"")
Note: It's an array formula and needs to be entered through CtrlShiftEnter
Drag down and right
AdvancedFilter (as you seem interested in that option too)
Just to add this option (involves some manual labour though)
If you set up your second sheet like so:
Formula in A2:
=">="&TEXT(TODAY()-WEEKDAY(TODAY(),2)+1,"yyyy/mm/dd")
Formula in A3:
="<="&TEXT(TODAY()-WEEKDAY(TODAY(),2)+1,"yyyy/mm/dd")
Now, it's important to initiate AdvancedFilter from the sheet you want to pull data into. And assign the appropriate ranges
Result looks like:
To auto-update this AdvancedFilter, you need a simple piece of VBA, so paste the following as a Worksheet_Change() event on Sheet1:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range, rng2 As Range
Dim lr1 As Long, lr2 As Long
With Sheet1
lr1 = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng1 = .Range("A1:C" & lr1)
End With
With Sheet2
lr2 = .Cells(.Rows.Count, 1).End(xlUp).Row
If lr2 > 3 Then
Set rng2 = .Range("A5:C" & lr2)
rng2.ClearContents
End If
rng1.AdvancedFilter xlFilterCopy, .Range("A1:C3"), .Range("A5")
End With
End Sub
Now you'll be able to add data in Sheet1 and it will auto-update the AdvancedFilter, which will be fast. But if you want to stay away from VBA, definately go with the formulas provided by either myself, or the more efficient approach with a ListObject by #RonRosenFeld.
sorry for being a total noob in excel!
I have two sheets, sheet 1 named "Stocks" and sheet 2 named "Stocks search".
In "Stocks" I have from A1 to B700 values. In A column I have the stocks symbols and in B column I have the stocks' issuers symbols, so every entry in A column is unique, yet there can be repeating entries in column B.
So in sheet "Stocks search", if I enter in A1 an issuer's symbol, I want for the formula to go search in sheet "Stocks" and fetch all stocks that this issuer has in new rows.
How can this be done in a formula? Thanks in advance!
This is a VBA solution to the question. IMHO, this is more appropriate than a formula (in this case). The formula approach is OK, but there are drawbacks - you have to remember the CSE rule, and then copy the formulas down the right number of rows (which you don't know in advance), etc, etc.
This code uses the same assumptions as the formula approach.
1 - sheets = Stocks and Stock report
2 - Data in Sheets, columns A and B (header in row 1)
3 - lookup code is on Stock report
4 - Output is on Stock report
One of the advantages is that if new data is added to the Stocks sheet (i.e. the bottom row > 700), the vba automatically adjusts.
The code is self-documented. But the essence is that it creates an autofilter on "Stocks" using the lookup value as the criterion; copies the rows that meet the criteria; and pastes the result to an output range on "Stock reports". The output range is cleared before the copy/paste takes place so that there are no left-overs from any previous lookup.
I think there's something to be said for creating a dropdown list for the lookup cell. No doubt that could be automated too by getting the codes from Column A, getting the unique values, and then apply them to the lookup cell. Just a thought;)
Sub so_52537740()
' CREDITS
'
' Refer: https://stackoverflow.com/questions/17531128/copy-paste-calculate-visible-cells-from-one-column-of-a-filtered-table
' Date: 8 July 2013
' Submitted by: Jon Crowell (https://stackoverflow.com/users/138938/jon-crowell)
Dim src As Worksheet, tgt As Worksheet
Dim filterRange As Range, copyRange As Range
Dim lastRow As Long
Dim stocks As String, stockreport As String
' set values for sheet names
stocks = "Stocks"
stockreport = "Stock report"
' set values for Sheet variables
Set src = ThisWorkbook.Sheets(stocks)
Set tgt = ThisWorkbook.Sheets(stockreport)
' clear the exist target data
tgt.Range("A4:B" & Rows.Count).ClearContents
' turn off any autofilters that are already set
If src.AutoFilterMode Then src.AutoFilter.ShowAllData
' find the last row in the Stocks sheet with data in column A
lastRow = src.Range("A" & src.Rows.Count).End(xlUp).Row
' the range that we are auto-filtering (all columns)
Set filterRange = src.Range("A1:B" & lastRow)
' the range we want to copy (only columns we want to copy)
' in this case we are copying both columns A and B
' we set the range to start in row 2 to prevent copying the header
Set copyRange = src.Range("A2:B" & lastRow)
' filter range based on column A being equal the the value in Cell A1 of the stockreport
' consider making this a dropdown list so that there are no errors
filterRange.AutoFilter field:=1, Criteria1:=Format(Sheets(stockreport).Range("a1").Value)
' copy the visible cells to our target range
' note that you can easily find the last populated row on this sheet
' if you don't want to over-write your previous results
copyRange.SpecialCells(xlCellTypeVisible).copy tgt.Range("A4")
' turn off any autofilters that are already set
If src.AutoFilterMode Then src.AutoFilter.ShowAllData
End Sub
Giving due credit: There is, as they say, nothing new under the sun. I have based this answer on an excellent piece of work by Jon Crowell on a question in StackOverflow "Copy/Paste/Calculate Visible Cells from One Column of a Filtered Table" in July 2013. Just goes to show what a bit of Googling and perseverance can achieve.
I believe I have an answer for you.
Try
=IFERROR(INDEX('Stocks Search'!$A$1:$A$700,SMALL(IF('Stocks Search'!$B$1:$B$700=$A$1,ROW('Stocks Search'!$A$1:$A$700)-MIN(ROW('Stocks Search'!$A$1:$A$700))+1),COLUMNS($A$1:A1))),"")
This is a CSE formula. What that means is once you enter it into cell B1, you will need to press Control+Shift+Enter. Once you do this, these brackets will appear around your formula {}
Click the fill button in the bottom right of the cell and drag the formula to the right (you will need to do this for as many cells as it is possible for answers). So if Company A has 40 possible answers, you will need to have this formula go at least 40 cells to the right.
The application of CSE formulas can be tricky. Essentially you need to go to the end of the formula in the formula bar, and then use Control+Shift+Enter.
I hope this helps.
I'm a rookie at vba.
I created a solution that works on a micro basis, but can't get the same code to run when I add additional parameters to that code.
I created a multiple choice quiz with answer cells which test against the answers on a separate (hidden) sheet. An adjacent cell shows Yes or No response. That functionality which I researched on the web works well. I'm trying to clear.contents for all the cells so that the user can complete the quiz, clear all responses to give it another go.
I have 395 questions which I created code to clear "Range("B2").ClearContents"
My subroutine has 395 such commands and takes 45-60 seconds. I'm looking for a more efficient solution. I don't want to clear the entire column only the 395 non-adjacent cells which have user input.
Sub Test_Clear()
Range("B2,B5,B7,B9,B11").ClearContents
End Sub
My list of cells is on Sheet2 D1:D395 Each cell in D1:D395 lists a cell on Sheet1 which I want to clear (i.e. B6, B11, B17, B22, B35 etc.) How can I reference those cells on Sheet2 and perform the ClearContents?
While you could just hard code your list in VBA instead of your Sheet2 range, here is how you could reference that list of cells in sheet2 and clear the contents all at once:
Sub clearall()
Dim rngCell, listCells As String
For Each rngCell In Sheet2.Range("D1:D395").Cells
If listCell <> "" Then listCell = listCell & "," & rngCell.Value Else listCell = rngCell.Value
Next
Sheet2.Range(listCell).ClearContents
End Sub
If you just want to clear the cells in column A which have something in them you could use this
Sheet1.Range("A:A").SpecialCells(xlCellTypeConstants).ClearContents
'or
Sheet1.Range("A1:A395").SpecialCells(xlCellTypeConstants).ClearContents
The VBA Join function can be used to join values into string, and the Excel Transpose function is needed to "flip" the column values 2D array to a 1D row values array:
stringAdress = Join([Transpose(Sheet2!D1:D395)], ",")
ThisWorkbook.Worksheets("Sheet1").Range(stringAdress).ClearContents
If any of the cells in the Sheet2!D1:D395 range are blank, the above will result in error.
In Excel 2016, the TextJoin function can be used to ignore empty cells (not tested):
stringAdress = [TextJoin(",", True, Sheet2!D1:D395)]
ThisWorkbook.Worksheets("Sheet1").Range(stringAdress).ClearContents
I have a list of >100,000 diagnosis codes in a .XLS document and need to extract from this all codes that are relevant to a number of specific diseases.
What I would like to be able to do is include all 100,000 diagnostic codes in Column A, diagnostic labels in column B, and then have a "search term" cell (e.g. C1) in which I can write a word such as "fracture".
I would then like all the diagnostic codes including the string "fracture" to appear in column D.
Is there a simple way of doing this in Excel? I have looked online without much success but this might be because I'm not certain where to start. Conditional formatting hasn't helped as it's still unmanageable to scroll through 100,000 codes even if they are highlighted nicely.
Any initial thoughts or tips as to what I could try searching for would be very welcome.
Sample dataset:
238 Fracture of proximal humerus
202 Aortic stenosis
990 Chronic obstructive pulmonary disease
302 Hip fracture
182 Recurrent fractures
094 Marfan syndrome
298 Diabetic retinopathy
We can use a helper column to find the matching rows. In E1 enter:
=MATCH("*" & $C$1 & "*",B:B,0)
and in E2 enter:
=IFERROR(MATCH("*" & $C$1 & "*",INDEX(B:B,E1+1):INDEX(B:B,999999),0)+E1,"")
and copy down. Column E tells us where the matches are.. Then in D1 enter:
=IFERROR(INDEX(A:A,E1),"")
and copy down:
This is a fairly standard way to do a keyword search.
I realize you didn't ask for a filter but if you are open to a slightly different solution this seems to work well. Column A title and values should start at cell A2. Then type your search term in cell B1. It will also filter with wildcards and is case insensitive (i.e. show fracture, Fracture, fractures, Fractures, fractured, Fractured).
Option Explicit
Sub Filter()
Dim MyArray() As Variant
Dim MyNewArray() As Variant
Dim i As Long
Dim item As Variant
Dim FilterRange As Range
With ActiveSheet
Set FilterRange = .Range(.Cells(2, 1), .Cells(.Rows.Count, 1).End(xlUp))
MyArray = Application.Transpose(FilterRange)
i = 0
For Each item In MyArray
If UCase(item) Like "*" & UCase(Range("B1")) & "*" Then
ReDim Preserve MyNewArray(i)
MyNewArray(i) = item
i = i + 1
End If
Next item
.Range(FilterRange.Address).AutoFilter Field:=1, Criteria1:=MyNewArray(), Operator:=xlFilterValues
End With
End Sub
Additionally, you could add the following in the Worksheet object so you don't have to click a button to run the macro:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("B1")) Is Nothing Then
Call Filter
End If
End Sub
Honestly, you can achieve the same thing with Filter > Text Filters > Custom Filter. You can use wildcards, too. :)
Let's say you want to search the term contained in C1 in column B.
You can try using this in A
=IF(C1<>"",IFERROR(FIND(C1,B1,1),0),0)
This will return a number if the text in C1 is present, else a 0.
You can then set D to be
=IF(A1>0,B1,"")
You will obtain this
I am putting the string to be searched for in the first row.
In row 2, I do a string match to get the first instance of a match for C1 in column A.
C2 =INDEX($A:$A,MATCH("*"&C1&"*",$A2:$A$100,0)+1)
Then find the next match starting from the array with row that matches C2 as the first row. I am fixing the last row as A100 which you can change.
C3 =INDEX($A:$A,MATCH("*"&$C$1&"*",INDIRECT("A"&MATCH(C2,$A:$A,0)+1&":A100"),0)+MATCH(C2,$A:$A,0))
Copy the formula down as required. Then copy columns across as required.
You can wrap the formula using IFERROR to suppress N/As.
You can also used an advanced filter in Excel by going to Data|Advanced:-
Note that the column headers in C1 and D1 must match the column headers in A1 and B1.
You can also adopt a DIY approach with:-
=IFERROR(INDEX(B:B,SMALL(IF(ISNUMBER(SEARCH($H$2,$B$1:$B$100000)),ROW($B$1:$B$100000)),ROW(1:1))),"")
assuming the search term is in H2, starting in say J2 and pulled down as necessary. This may be a little slow with 100K terms but is usable. Must be entered as an array formula with CtrlShiftEnter
I want to write a formula like =SUM(tab2!A:A) but instead use the column title of A which is say "count". How can I modify this to look more like: =SUM(tab2!"count")?
The reason I want to do this is because I copy and paste a spreadsheet from another source in tab2 and the column referring to "count" may be in a different column. I want the formula to give me the correct calculation as soon as I paste the new spreadsheet by automatically finding the column to sum up by title name.
I must be missing something because this seems like a very basic question and I can't find the answer anywhere...
Thanks for your help!
I like the idea of naming ranges proposed by #Doug, but if the issue is that you are dumping your data in [and you don't know in advance which column is going to be where] and would need to rename your range every time, there are other options - I suggest using OFFSET. OFFSET allows you to dynamically create a range, starting at a particular point and moving down/up / right/left for as many rows and columns as you determine.
In your case, you will need to combine that with a method for searching the columns to see which one says "Count". I am assuming that your column headings are always in row 1. If they aren't [or if they aren't always in row 2, or any row you know in advance]... you can get around that but then I'd recommend you try to make your data more uniform instead of creating unnecessary Excel workarounds.
In total your formula would look like this:
=SUM(OFFSET(A1,,MATCH("Count",1:1,0)-1,ROWS(A:A),1))
What this does is first determine which column the word "Count" is found in, in row 1. Then it subtracts 1 from that number - this now equals the number of columns to the right that it is, from column A. It uses offset to create a reference to that column, for all rows, and sums those rows together.
Check out the name manager for naming ranges :)
You didn't say whether you would consider a macro solution. If so, this may work.
If the sheet you are pasting into is Sheet2 and the sheet you want the result in is Sheet1, then this macro, if placed in the Worksheet_Activate event of Sheet1 will give you the result as soon as you click on the Sheet1 tab afetr pasting your data into Sheet2:
Private Sub Worksheet_Activate()
Dim r As Range
Dim rCol As Range
Dim rFound As Range
Dim ws As Worksheet
Dim lTotal As Long
Set ws = Sheet2
Set r = ws.Cells
Set rFound = r.Find("count")
If Not rFound Is Nothing Then
Set rCol = rFound.EntireColumn
lTotal = Application.WorksheetFunction.Sum(rCol)
End If
Cells(1, 1) = lTotal
End Sub
It does assume there is only one cell with the word "count" in it on Sheet2.