I have a sheet with exact values (verified by =a2=b2 returning true).
However, =match(a2,b2,0) returns #N/A for some values, but not all.
All cells are formatted the same (I've tried General, Text, Number, etc.), and I have no idea where to go from here.
I don't know if I can upload my test workbook here so here's an image:
Maybe run a quick macro on the relevant cells in columns A and B:
Sub Clean_Up()
For Each r In Range("A2:B8")
r.Value = Val(r.Value)
Next r
End Sub
Adjust range (A2:B8 here) to suit.
Regards
Related
I am looking for reverse vlookup with more than 255 characters in Excel VBA.
This is the formula based one which I took from this website.
=INDEX(F2:F10,MATCH(TRUE,INDEX(D2:D10=A2,0),0))
I have try to convert it in VBA. Here below sample code
Sub test()
'concat
Range("i1") = WorksheetFunction.TextJoin(" ", True, Range("g1:h1"))
'lookup
Sal1 = Application.WorksheetFunction.Index(Sheets("sheet1").Range("a1:a2"), Application.WorksheetFunction.Match(True, Application.WorksheetFunction.Index(Sheets("sheet1").Range("i1:i1") = Range("i1").Value, 0), 0))
'=INDEX($W$3:$W$162,MATCH(TRUE,INDEX($W$3:$W$162=U3,0),0))
End Sub
It works well but it didn't when i change the range("i1:i1") to range("i1:i2")
I'm not sure what that worksheet formula does that =INDEX(F2:F11,MATCH(A2,D2:D11,FALSE)) doesn't do.
This part Index(Sheets("sheet1").Range("i1:i2") = Range("i1").Value, 0) is comparing a 2-d array to a single value, which should result in a Type Mismatch error. Whenever you reference a multi-cell range's Value property (Value is the default property in this context), you get a 2-d array even if the range is a single column or row.
You could fix that problem with Application.WorksheetFunction.Transpose(Range("D1:D10")) to turn it into a 1-d array, but I still don't think you can compare a 1-d array to a single value and have it return something that's suitable for passing into INDEX.
You could use VBA to create the array's of Trues and Falses, but if you're going to go to that trouble, you should just use VBA to do the whole thing and ditch the WorksheetFunction approach.
I couldn't get it to work when comparing a single cell to a single cell like you said it did.
Here's one way to reproduce the formula
Public Sub test()
Dim rFound As Range
'find A2 in D
Set rFound = Sheet1.Range("D1:D10").Find(Sheet1.Range("A2").Value, , xlValues, xlWhole)
If Not rFound Is Nothing Then
MsgBox rFound.Offset(0, 2).Value 'read column f - same position as d
End If
End Sub
If that simpler formula works and you want to use WorksheetFunction, it would look like this
Public Sub test2()
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
MsgBox wf.Index(Sheet1.Range("F2:F11"), wf.Match(Sheet1.Range("A2").Value, Sheet1.Range("D2:D11"), False))
End Sub
Function betterSearch(searchCell, A As Range, B As Range)
For Each cell In A
If cell.Value = searchCell Then
betterSearch = B.Cells(cell.Row, 1)
Exit For
End If
betterSearch = "Not found"
Next
End Function
i found this code from above link and it is useful for my current search.Below examples i try to get value..
Kindly consider Row 1 to 5 as empty for A and B column because my table always start from Row 6
Row
A Column
B Column
6
54
a
7
55
b
8
56
c
VBA Code:
Sub look_up ()
Ref = "b"
look_up = betterSearch(Ref, Range("B6:B8"), Range("A6:A8"))
End Sub
it show Empty while use Range("B6:B8"), Range("A6:A8")
but when changing the range from B6 and A6 to B1 and A1 (Range("B1:B8"), Range("A1:A8") )it gives the value...
My question is "can get the values from desired range"
Expressing matches via VBA
I like to know if there (are) any possibilities to convert this formula.
=INDEX(F2:F10,MATCH(TRUE,INDEX(D2:D10=A2,0),0))
So "reverse VLookUp" in title simply meant to express the (single) formula result via VBA (btw I sticked to the cell references in OP, as you mention different range addresses in comments).
This can be done by simple evaluation to give you a starting idea:
'0) define formula string
Dim BaseFormula As String
BaseFormula = "=INDEX($F$2:$F$10,MATCH(TRUE,INDEX($D$2:$D$10=$A2,0),0))"
'1) display single result in VB Editor's immediate
Dim result
result = Evaluate(BaseFormula)
Debug.Print IIf(IsError(result), "Not found!", result)
On the other hand it seems that you have the intention to extend the search string range
from A2 to more inputs (e.g. till cell A4). The base formula wouldn't return a results array with this formula,
but you could procede as follows by copying the start formula over e.g. 3 rows (note the relative address ...=$A2 to allow a row incremention in the next rows):
'0) define formula string
Dim BaseFormula As String
BaseFormula = "=INDEX($F$2:$F$10,MATCH(TRUE,INDEX($D$2:$D$10=$A1,0),0))"
'2) write result(s) to any (starting) target cell
'a)Enter formulae extending search cells over e.g. 3 rows (i.e. from $A2 to $A4)
Sheet3.Range("H2").Resize(3).Formula2 = BaseFormula
'b) optional overwriting all formulae, if you prefer values instead
'Sheet3.Range("H2").Resize(3).Value = Tabelle3.Range("G14").Resize(3).Value
Of course you can modify the formula string by any dynamic replacements (e.g. via property .Address(True,True,External:=True) applied to some predefined ranges to obtain absolute fully qualified references in this example).
Some explanations to the used formulae
The formula in the cited link
=INDEX(F2:F10,MATCH(TRUE,INDEX(D2:D10=A2,0),0))
describes a way to avoid an inevitable #NA error when matching strings with more than 255 characters directly.
Basically it is "looking up A2 in D2:D10 and returning a result from F2:F10" similar to the (failing) direct approach in such cases:
=INDEX(F2:F11,MATCH(A2,D2:D11,FALSE))
The trick is to offer a set of True|False elements (INDEX(D2:D10=A2,0))
which can be matched eventually without problems for an occurence of True.
Full power by Excel/MS 365
If, however you dispose of Excel/MS 365 you might even use the following much simpler function instead
and profit from the dynamic display of results in a so called spill range.
That means that matches can be based not only on one search string, but on several ones (e.g. A1:A2),
what seems to solve your additional issue (c.f. last sentence in OP) to extend the the search range as well.
=XLOOKUP(A1:A2,D2:D10,F2:F10,"Not found")
So I have built a formula that has Absolute Cell References, and wanted to repeat the same formula down 3000 cells with each one referencing increment cells. (1st formula referring to Cell $A$1, 2nd formula referring to $A$2) I know that I could easily do this without referencing exact cells and the Fill Handle and this is currently how it's set up, however there's a very large number of people who work in this spreadsheet that have bad Excel manners, and regularly delete rows and cells or copy and paste, which breaks the formulas.
Rather than manually editing the same formula in each cell to change the references from relative to absolute, I was wanting to run a Macro to automatically run the formula for 3000 cells.
I had at first built a Macro that fills 20 cells with the formula, but it didn't adjust the formula based on the active cell. (Always entered with range $A$1:$A$20, and not $A$21:$a$40 when started further down) I changed the Macro to loop, but it looks with all formulas referencing $A$1 rather than updating.
The Macro set up to loop is as follows:
Sub HDDatesRef()
ActiveCell.Select
ActiveCell.FormulaR1C1 = "=IF(AND(HD!R1C1>0,ISBLANK(HD!R1C4)),HD!R1C1,""n/a"")"
ActiveCell.Offset(1, 0).Range("A1").Select
Loop Until ActiveCell.Value = ""
End Sub
Any and all help with figuring this out would help immensely. Right now I also have access to Liknedin Learning, so if there's any suggestions for courses on there I should look into so I can understand what I need to do will help with this.
The Excel application object has a function called ConvertFormula which you can use to change a formula between reference styles (A1 or R1C1) and to specify whether the rows and columns should be relative references or absolute references.
If you start off by creating the formula in each row as a relative reference then you can use ConvertFormula to turn it into an absolute reference. The only restriction is that the formula cannot be longer than 255 characters.
Adapting your code and following the advice in How to avoid using Select in Excel VBA gives us:
Option Explicit
Sub HDDatesRef()
Dim r As Range
' If we know the cell address we want to start in then we could use that directly
' e.g. Set r = Worksheets("HD").Range("E1")
Set r = ActiveCell
Do
' The With block just saves us typing r.FormulaR1C1 multiple times
With r
' Don't know what your relative formula would be. I've assumed that we are
' working in column E but adjust as appropriate
.FormulaR1C1 = "=IF(AND(HD!RC[-4]>0,ISBLANK(HD!RC[-1])),HD!RC[-4],""n/a"")"
' Take the formula we already have which is in R1C1 format, keep it in R1C1 format,
' change it from a relative reference based on cell r to an absolute reference
' and make that the new formula for this cell
.FormulaR1C1 = Application.ConvertFormula(.FormulaR1C1, xlR1C1, xlR1C1, xlAbsolute, r)
End With
' Move down one row
Set r = r.Offset(1, 0)
Loop Until r.Value = ""
End Sub
In case you aren't familiar with them. here are the references for Option Explicit and With...End With
You can do this without looping, Excel is smart enough to know you want incremental.
As an example do run this on a fresh sheet:
Sub ShowIncremental()
Range("A1:A10").Formula = "=Row(A1)"
Range("B1:B10").Formula = "=A1*2"
Range("C1:C10").Formula = "=sum(B$1:B1)"
End Sub
Notice the formulas created in A1:C10. Notice Excel incremented them even though the code didn't say to except in the case where we absoluted B$1.
I recommend you do something similar with your code to avoid looping, this will be much much faster.
I want to use the Find and Replace in Excel to remove all zeroes from a column that holds say the values of column A-column C. So A2-C2, A3-C3 etc. But because its a formula it just wont work even though I have tried the 'match case/Match Entire contents' as well as other combinations in Options. This is a simple question but hard finding an answer as all questions seem to be directed at finding a part of a formula and replacing with something else.
If you do not want to see a "0" or "#VALUE!" in these columns, I would rewrite the formula such that it excludes these values as outputs (meaning any sum or avg function would exclude these cells). Try using either "iferror" or "if" formulas to exclude see examples below.
Excluding 0 using if statement: =IF(H8*G8 = 0,"",H8*G8)
Excluding #Value! using iferror: =IF(H8*G8 = 0,"",H8*G8)
Excluding 0 and #value using combined iferror/if statement: =IFERROR(IF(G20*H20 = 0," ",G20*H20),"")
If you want to exclude both 0s and #value! you can combine the formulas:
enter image description here
Assuming you do not want to rewrite the whole range of formulas, you dan do it via VBA (hit Alt+F11).Just paste that code somewhere in there. Now select the range you want to empty out of 0's and #Errors and run the code:
Sub RemZeroErr()
Dim rng As Range
For Each rng In Intersect(Selection, Selection.Parent.UsedRange).Cells
If IsError(rng) Then
rng.Value = ""
ElseIf rng.Value = 0 Then
rng.Value = ""
End If
Next
End Sub
First time posting for me and hoping to get some help with VBA for selective hardcoding.
I currently have a column into which a formula is set which returns either blank or a variety of text strings (the status of our company's orders).
I need to make a macro that looks into all the cells of that column and copy/pastes as value into that same cell only if the formula in that cell returns text string "Received". It should not affect the other cells where the formula is returning either blank or a different text string.
Would really appreciate your help. Please let me know if you need more info.
Thanks in advance,
Olivier
Put the following in the VBA project of your workbook:
Option Compare Text
Sub replaceThem()
Dim r As Range
Dim c
Set r = Range("B1:B3") ' use the actual range here
For Each c In r
If c.Value = "Received" Then c.Formula = "Received"
Next
End Sub
This will do what you asked. c.Value returns the value of the formula in the cell c, c.Formula replaces the formula. The Option Compare Text makes the comparison case-insensitive.
The two columns look like on this image.
When I want to show only the cells which contain a letter 'b', I can no longer see the text "Title1" and "Title2" which is normally visible in the column B.
I guess although the cells in column B are merged, the text is still bound to A3, respectively to A7.
So how can I at the same time filter the visible content and preserve the merged text? In simple words, I want to filter content by letter 'b' and I still want to see the text "title 1/2" in the column B.
You tagged excel so here is a solution in excel:
You need to click on that column with the merged cells and unmerge all cells.
Then you need to put this formula at the top of your list and enter it with ctrl+shift+enter(this will enter it as an array formula):
=OFFSET(C3,MAX(IF(NOT(ISBLANK(C$3:C3)),ROW(C$3:C3),0))-ROW(C3),0)
Then you need to autofill that down.(this function seems a little verbose but I just got it online - there is probably a simpler way to do this - but it finds the last nonblank cell in a range).
I think openoffice has similar functions so you should be able do the same or something similar in openoffice.
Alternatively if you are using excel you could click on the column you want to unmerge and run this macro:
Sub UnMergeSelectedColumn()
Dim C As Range, CC As Range
Dim MA As Range, RepeatVal As Variant
For Each C In Range(ActiveCell, Cells(Rows.Count, ActiveCell.Column).End(xlUp))
If C.MergeCells = True Then
Set MA = C.MergeArea
If RepeatVal = "" Then RepeatVal = C.Value
MA.MergeCells = False
For Each CC In MA
CC.Value = RepeatVal
Next
End If
RepeatVal = ""
Next
End Sub
Good Luck.
EDIT:
I found a Non-VBA solution that will work in both excel and openoffice and doesn't require you to enter it as an array formula(with ctrl+shift+enter):
=INDEX(B:B,ROUND(SUMPRODUCT(MAX((B$1:B1<>"")*(ROW(B$1:B1)))),0),1)
In open office I think you want to enter it like this:
=INDEX(B:B;ROUND(SUMPRODUCT(MAX((B$1:B2<>"")*(ROW(B$1:B2)))),0),1)
or maybe like this:
=INDEX(B:B;ROUND(SUMPRODUCT(MAX((B$1:B2<>"")*(ROW(B$1:B2)))),0))
You just need to autofill that formula down:
Your main problem seems to be the one "blank row" that you have left after the filter fields.
Remove it, and it will work fine.