how can I use a variable in a INDEX & MATCH statement - excel

I'm using Excel 2010 and have a vba statement that works using hardcoded range limits, as below
Range(Range("F2"), Range("F" & lrow)).Value = "=INDEX('Acc plan'!$D$2:D300,MATCH(sageTB!$A$2:A300,'Acc plan'!$A$2:A300))"
I'd like to replace the value of 300 with a variable, but so far have failed miserably to get a version that doesn't just result in hash NAME in the results cell. Any tips would be very welcome

Related

Add Cell value into URL to find Data vba

I am trying to replace 558899 this Id number from below URL with cell value that is ID_NO = ws.Range("A1").Value.
"15.156.352.352/api/Book/GetOrBookID?Id=558899&ColumnName=PrimaryId"
and i changed it to
"15.156.352.352/api/Book/GetOrBookID?Id=" & ID_NO & "ColumnName=PrimaryId"
But it does not work nay help will be appreciated.
Your question doesn't mention what the bad result is, but I can see one issue in your code:
"15.156.352.352/api/Book/GetOrBookID?Id=" & ID_NO & "ColumnName=PrimaryId"
When this is parsed, it will result in:
"15.156.352.352/api/Book/GetOrBookID?Id=xxxxColumnName=PrimaryId"
But I think you want:
"15.156.352.352/api/Book/GetOrBookID?Id=xxxx&ColumnName=PrimaryId"
So the code you need is:
"15.156.352.352/api/Book/GetOrBookID?Id=" & ID_NO & "&ColumnName=PrimaryId"
Im guessing that the cell value is formatted as a number(long). therefore you could try replacing ID_NO with str(ID_NO) to convert it to a string

MATCH and INDEX to return index number 2 Excel

I tried with the combination of CONCATENATE, INDEX and MATCH function, to get an overview table of which employees works which function a day.
Here is the setup:
And this should be the resulting table:
This is the formula I made:
=CONCATENATE(INDEX($B$5:$B$10,MATCH($B2,C$5:C$10,0)))
And obtain only the first index:
How can a return index 2 respectively: name3 and name5?
I have an Excel version prior to the 2016 version, and can't use the TEXTJOIN or CONCAT function.
EDIT
I tried to make the formula work even though the VBA solution works as well:
This is what I get to work:
=IF(COUNTIF(C$5:C$10,$B2)=0,"",IF(COUNTIF(C$5:C$10,$B2)=1;INDEX($B$5:$B$10,MATCH($B2,C$5:C$10;0)),INDEX($B$5:$B$10,MATCH($B2,C$5:C$10,0))&CHAR(10)&INDEX($B$5:$B$10,SMALL(MATCH($B2,C$5:C$10),ROWS(C$5)))))
It gives the correct solution in this case (assuming there are at most 2 matches), however it's fragile.
I tested it in a larger setup, where it returned the same name twice, and I can't figure out what the problem is.
Any idea, why that's the case?
Nothing pretty at all. But it does work.
User defined function.
Place this code in a module
Function name_find(func As String, namerng As Range, searchrng As Range)
For Each r In searchrng
If r.Value = func Then
name_find = name_find & Chr(10) & Cells(r.Row, namerng.Column).Value
End If
Next r
End Function
and use the formula:
=name_find(C4,C9:C14,D9:D14)
Remember to enable line breaks in the cell. It took me a while to understand why it didn't work :-)

Possible faster VBA lookup with wildcards?

I need to perform a quite a lot of lookups with wildcards on the worksheet using a macro (mainly lookup for value & returning the value from another column though with proper adjustment it can be also just looking for a value with wildcard, and some lookups only as checks if the value exists in the dataset). My data can't be sorted and all the lookups are within a loop A or loops within loop A; wildcards are included mostly for condition "string begins with...". I often have to find a value in one row and find corresponding value in row N rows below or above.
I have a working code, but I wonder if it can be done faster. #response to comment about posting it on Code Review (sorry, I cannot comment yet :)) - preparation the whole code to posting would take a bit too much time for me, confidentiality etc, so I prefer to treat it as a general question to be worked on this example.
Example data (I can add more columns, if I need any helper column):
Example Data picture at Imgur
Assume 100 000 rows (max xPagesCount = 1000, typically around 400; all values for certain xPage is in one block). Due to a lot of possible rows with additional data I can't simply find one value and add numbers to the found row to find the other values by their position.
Example lookups to perform while looping through consecutive xPages (so, for each given xPage):
value in row just below row with "RESTRICTIONS:" text
find name (which is always given with height (column C) = 35)
find RSW number (which can be in several rows depending on page content, but always below name)
find all rows starting with the same four digits as RSW, in two formats: DDDD.LLL.DD and DDDD.DDDDD.DD (L letter, D digit) (I use internal loop here)
check if there is a text "MASTER" (or "MASTER " etc.)
find all values between values "DOCUMENTS:" and "OPTIONS:", which quantity can be from 1 to 50 (I use internal loop here)
I was wondering, what is the fastest way to do such lookups?
What I tried:
using a dictionary on all dataset (keys in column A or C with, values
col.D) but as dictionary can't work on wildcards, I had to add ifs
for not finding a key to perform additional Application.Match
lookup... and then realized it mostly worked on these Match lookups
and not sure I even need a dictionary. I also have duplicate values
within a page and dictionary was getting only first value, regardless
their position (for example, several attachments could have value 1).
The main use remained dict.exists("MASTER") but when I removed
dictionary and changed it to IsError(Application.Match(...)) the code
worked slightly faster.
Application.Match in whole range, typical example: Application.Match(xPage & "4???.*", sh.Range("A1:A" & LastRow), 0)
in few places I use If xValue Like "????.???.??" Then construction
I have dictionary lookups with ifs redirecting to Application.Match:
xValue = dict(xPage & "ATH.416")
If dict(xPage & "ATH.416") = "" Then xValue = Application.Match("ATH.*", Sheets(1).Range("D:D"), 0)
What I consider, but not sure it's worth the effort:
altering the code that at the beginning of the iteration I find the first and the last row for xPage, and then each later check is performed in this range
xStartPage = sh.Range("D" & Application.Match(xPage, sh.Range("A1:A" & LastRow), 0))
'or, I guess better:
xStartPage = xEndPage + 1
If xPage = xPagesCount Then
xEndPage = LastRow
Else
xEndPage = sh.Range("D" & Application.Match(xPage + 1, sh.Range("A1:A" & LastRow), 0) - 1)
End If
xValue = sh.Range("D" & Application.Match("4???.*", sh.Range("D" & xStartPage & ":D" & xEndPage), 0)).Value

Comparing Strings Producing Unexpected Results

I have a list of data and I created a form to enter new data to be added to the list. Upon the click of a button it will take the information (name and email address) from the form and add it to the corresponding sheets in alphabetical order. There are linked cells involved so I can't just add this to the bottom and sort. Instead, I have it searching the last name cell in the correct sheets to insert a row into the correct location.
This was working as expected for the most part until I came along a possibly unique situation that I can't figure out.
Basically, I have an if statement checking to see if the name is a duplicate and afterwards checking to see if the if the new name should be inserted.
For i = 2 To lastrow
''^^IF STATEMENT CHECKING FOR DUPLICATE^^''
'''''''''''''''''''''''''''''''''''''''''''
'''vvIF STATEMENT CHECKING TO ADD DATAvv'''
ElseIf StrComp(lastname, searchl) = 1 And StrComp(lastname, searchl2) = -1 Then
Sheets("Master List").Range("A" & i).Offset(1).EntireRow.Insert (xlDown)
Sheets("Master List").Range("A" & i + 1).Value = firstname
Sheets("Master List").Range("B" & i + 1).Value = lastname
Sheets("Master List").Range("C" & i + 1).Value = fullname
Variables searchl and searchl2 are the last names from search rows i and i + 1, respectively.
My problem is that when I tried to add the last name "Kralik" it tried to insert the data between the last names "Day" and "de Castro"
Originally, I tried comparing the names using the line of code below:
ElseIf lastname > searchl And lastname < searchl2 Then
This executed the exact same way as the code outlined above. I then inserted a break point and decided to use the StrComp method for troubleshooting. Comparing "Kralik" to "Day" produced results expected but the problem occurs when comparing "Kralik" to "de Castro". For some reason, the code thinks "Kralik" is less than "de Castro" and enters the if statement to insert the data at that location. Even more head scratching for me is that I opened a new workbook and quickly typed "Kralik" into A1, "de Castro" into A2 and the formula "=A1>A2" into A3. The formula gave a result TRUE which is what I would have expected from VBA as well.
EDIT: After more tests, I think it must have something to do with the capitalization of "Kralik" vs. "de Castro" my code works as expected as long as the "k" in "Kralik" is uncapitalized. I will use the UCase method on my variables and come back with the results.
EDIT 2: Using UCase works as well. Outlined by GSerg's answer below as to why my original method was not working.
Excel formulas use case insensitive comparisons by default.
VBA uses case sensitive comparisons by default.
If you want case insensitive comparisons, either put
Option Compare Text
at the beginning of the code module to make all text comparisons in that code module case insensitive by default, or request a comparison type in each specific comparison:
ElseIf StrComp(lastname, searchl, vbTextCompare) = 1 And StrComp(lastname, searchl2, vbTextCompare) = -1 Then
On top of that, you should be using binary search in your particular case to find the position to insert. MATCH with match_type = 1 will return you position in a sorted list where the value should go.

Excel VBA behaves different in different languages

Win-XP, Excel 2003
I have a range defined by a name, which is filled by a query. The same named range forms the source of a cell validation (in-cell dropdown list). In my VBA this range is accessed via a range object named LOVL2.
Each time the range is re-filled by the query, its name is redefined to include all rows I obtained through the query. This is done with statement
LOVL2.CurrentRegion.Name = LOVL2.Name.Name
the statement works fine as long as MS Office language is set to English, but the statement fails when MS office language is set to French .... I get Error 1004 "Invalid Name"
Anyone got an idea what is causing this only when MS Office language is set to FRENCH but not while in ENGLISH? (maybe problem with ";" vs "," within the object ??)
Thanks in advance MikeD
edit 12-Aug-2010
the REAL root cause is clear now:
the range's name is "L2PoP" which in the ENGLISH version is recognized as a valid name for a range - in that you can go to any empty sheet, select a range and name it "L2PoP".
Set your user language to FRENCH, go to any empty sheet, select a range and name it "L2PoP", and you get an error saying "Nom non valide".
so the real curing action is to give a different name to the range which is accepted by both French and English
I can only speculate about what is causing this, it may have to do with the fact that the first 2 characters look like a cell address, on the other hand "A1PoP " is a valid name, whereas "L2Foo" and "L1Foo" are invalid.
strange, but .....
which is filled by a query
By a query table?
A query table's result range already has a name which is the name (a bit sanitised) of the query table itself (set in the properties dialog). Which means you don't need to redefine anything.
And if you do, then try this code:
Sub asfgsdfg()
Dim n As Name
Set n = ThisWorkbook.Names("LOVL2")
'Or in case of a local name,
'Set n = ThisWorkbook.Worksheets("The worksheet").Names("LOVL2")
ChangeNamedRangeAddress n, n.RefersToRange.CurrentRegion
End Sub
Public Sub ChangeNamedRangeAddress(ByVal n As Name, ByVal NewRange As Range)
n.RefersTo = "='" & Replace(n.RefersToRange.Worksheet.Name, "'", "''") & "'!" & NewRange.Address(True, True, xlA1)
End Sub
EDIT
In regard to the follow-up... Most strange and amusing.
Try using a leading underscore or something?

Resources