Excel VBA behaves different in different languages - excel

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?

Related

Vlookup based on criteria

The data I have in my "entity sheet"
entity id
source id
source entity id
HR0001
GOP
1200
HR0002
WSS
WSS1201
HR0003
GOP
1201
HR0004
WSS-T
WSST1202
HR0005
GOP
1202
HR0006
GOP
1203
HR0007
WSS-S
WSSS1203
HR0008
GOP
1204
HR0009
GOP
1205
HR0010
GOP
1206
HR0011
WSS-R
WSSR1204
HR0012
WSS-T
WSST1205
HR0013
WSS-S
WSSS1206
HR0014
GOP
1207
HR0015
WSS-T
WSSS1207
HR0006
WSS-S
WSSS1208
HR0007
GOP
1208
HR0008
WSS-R
WSST1209
HR0009
WSS-S
WSSS1210
In my working sheet, I need the source entity id (column c) data, by doing a VLOOKUP on the entity id (column A), based on source id (column b). that is I need only those beginning with "WS" IDs on my working sheet. My code is
Sub Test()
Worksheets("working sheet").Activate
Dim sht, sht1 As Worksheet
Dim i As Long, LR As Long
Set sht = ActiveWorkbook.Worksheets("working sheet")
Set sht1 = ActiveWorkbook.Worksheets("entity sheet")
LR = sht.UsedRange.Rows.Count
With sht
For i = 2 To LR
If InStr(sht1.Range("B" & i).Value, "WS") Then
sht.Range("B" & i).Value = (Application.VLookup(.Range("A" & i).Value, Worksheets("entity sheet").Range("A2:C5000"), 3, False))
End If
Next i
End With
End Sub
desired result - in the working sheet
entity id
source entity id - WSS
HR0001
HR0002
WSS1201
HR0003
HR0004
WSST1202
HR0005
HR0006
WSSS1208
HR0007
WSSS1203
HR0008
WSST1209
HR0009
WSSS1210
HR0010
HR0011
WSSR1204
HR0012
WSST1205
HR0013
WSSS1206
HR0014
HR0015
WSSS1207
Took me a little while but... I've got two different versions for you: one with VBA and one with just formulas.
With VBA
The issue you had was that VLOOKUP returns the first match but you needed to satisfy two criteria (that is: (i) match on entity id and (ii) match on source id begins with "WS").
This meant that you either had to:
use a formula that could match both criteria at the same time, OR
find all matches with the first criteria (e.g. with FIND) and then loop through the results to match the second criteria -- probably something like this: https://www.thespreadsheetguru.com/the-code-vault/2014/4/21/find-all-instances-with-vba
I selected option #1 as I expected it would make the code shorter.
To do this, I took advantage of a trick I've used in formulas before where I can use "&" between two ranges to match on two criteria at the same time. So, instead of matching "HR0012" first and then "WS-something" second, I match "HR0012WS-something" at once. (You can view this concept by pasting =A2:A20&B2:B20 in an empty column somewhere in your entity sheet.)
The following code assumes that your active worksheet is your working sheet. Paste this code behind your working sheet, then run it when you have that sheet open.
Public Sub tester()
Dim rg As Range
Dim sSourceEntityId As String
For Each rg In Range("A2:A16")
sSourceEntityId = Evaluate("=XLOOKUP(""" & rg.Value & "WS"",entity!A2:A20&LEFT(entity!B2:B20,2),entity!C2:C20,"""",0,1)")
If Len(sSourceEntityId) > 0 Then
rg.Offset(0, 1).Value = sSourceEntityId
End If
Next rg
End Sub
If the part inside the Evaluate is not clear, paste
=XLOOKUP(A1&"WS",entity!A2:A20&LEFT(entity!B2:B20,2),entity!C2:C20,"",0,1)
somewhere inside your working sheet to see it more clearly.
Also, note that you used Instr, which would find "WS" anywhere in the string. I used LEFT(value, 2)="WS" to be sure that I matched only the first 2 characters.
I also had to use XLOOKUP instead of VLOOKUP to allow me to use the LEFT(value, 2). If you're using an old version of Excel, you won't have XLOOKUP, unfortunately.
Without VBA
Paste this formula into A2 on your working sheet:
=IFERROR(INDEX(entity!$C$2:$C$20,AGGREGATE(15,3,((entity!$A$2:$A$20&LEFT(entity!$B$2:$B$20,2)=A2&"WS")/(entity!$A$2:$A$20&LEFT(entity!$B$2:$B$20,2)=A2&"WS"))*ROW(entity!$A$2:$A$20)-ROW(entity!$A$1),1)),"")
Then copy that formula down to every row that you want to do a match on. Just to be clearer, it will look like this:
This is a little complex. I based it on an approach in this article, which explains step-by-step how to use INDEX(.. AGGREGATE(..)) for multiple matches. Although it's pretty neat how it works, you may prefer the VBA approach as it is probably easier to maintain.
UPDATE:
I forgot to mention that there is a possibility that the IFERROR() in the formula may slow your spreadsheet down if you have many matches and rows. I also created a version of the formula that doesn't use IFERROR. It uses an IF to first check if there are any TRUE matches first before executing the INDEX.. AGGREGATE. You may not need it, but I've pasted it below just in case it's useful:
=IF(MAX(INT(entity!$A$2:$A$20&LEFT(entity!$B$2:$B$20,2)=A2&"WS"))=1,INDEX(entity!$C$2:$C$20,AGGREGATE(15,3,((entity!$A$2:$A$20&LEFT(entity!$B$2:$B$20,2)=A2&"WS")/(entity!$A$2:$A$20&LEFT(entity!$B$2:$B$20,2)=A2&"WS"))*ROW(entity!$A$2:$A$20)-ROW(entity!$A$1),1)),"")
UPDATE 2:
The statement used in the VBA Evaluate will also work directly as a formula and is much simpler to understand. I realized this when I realized that a single valid match is okay (i.e. we don't need multiple matches):
=XLOOKUP(A2&"WS",entity!$A$2:$A$20&LEFT(entity!$B$2:$B$20,2),entity!$C$2:$C$20,"",0,1)

VBA Vlookup errors

I have written vlookups plenty of times but dont have any of my old code examples to hand and I know I am missing something really simple here.
Context - I am creating a code workbook separate from the file to work on. I have created a function that creates an order ID and during that process I have to lookup a value and swop it for the value of the look up. I am absolutely certain I am simply not getting the syntax right for the sheet referencing part of the lookup but despite checking various posts on here and changing it several times I cannot get it right
Function build_order_ID(building_name As String, customer_name As String, order_number As Integer)
Dim building_name_new As String
building_name_new = WorksheetFunction.VLookup(building_name, ThisWorkbook.Sheets("building_ref").Range("A1:B5"), 2, False).Value
build_order_ID = building_name & "-" & order_number & "-" & customer_name
End Function
The sheet is sheet3 but named building_ref
I am using this code to generate the output but it always stops during the lookup normally with object errors but I did get different errors when changing the format of calling the sheet
Public Sub test_order_ID()
Dim order_ID As String
order_ID = build_order_ID("testvalue", "Jack", 1)
MsgBox order_ID
End Sub
Thank you to https://stackoverflow.com/users/9245853/bigben who pointed out my error with the .value at the end of the vlookup. After removal the code executed correctly

Searching for Specific Column Headers in Excel File - Runtime Error 91

I am attempting to write some excel vba code that will process the content of certain columns of data. Given the worksheet has some level of dynamic change (columns added and removed from time to time), I want my code to "find" the specific columns by their header names, and ultimately return the column number. My File has roughly 50 columns.
The problem is this: My code works just fine to find many of the columns (headers) I am interested in returning the column index, but some of the columns "while clearly existing", will return Nothing and thus, throws the runtime 91 error.
I can say, without a doubt that when I execute the .find, that truly, the columns DO exist (like the Comments column). I can randomly change the failing hdr search column to a different header name, passing it to the function in the code and some columns are found just fine, and other, cause the runtime error. I have checked the "failing" headers for special characters, blanks, LF's etc. No luck. Even tried re-ordering the 4 rows using FindColHdrNum function. Again, no luck.
Was hoping fresh eyes may provide answer. Simplified code is below which is triggered by a button on main excel worksheet. I have not worked with functions much in VBA, and even where the function does not generate the Runtime Error, it is not returning the column value, but this is a secondary problem I can work on once I get the find code not blowing up (returning 0).
Sub Button119_Click()
Dim L4RankCol As Integer
Dim DecomDriverCol As Integer
Dim SupTermImpactYrCol As Integer
Dim Comments As Integer
Dim L3RankCol As Integer
L4RankCol = FindColHdrNum("L4 Rank") '<-- This works
DecomDriverCol = FindColHdrNum("Decom Driver") '<-- This works
SupTermImpactYrCol = FindColHdrNum("Support Termination Impact Yr") '<-- This works
Comments = FindColHdrNum("Comments") '<-- This does not work
End Sub
Function FindColHdrNum(strHdr As String) As Integer
Dim rngAddress As Range
Set rngAddress = Range("Headers").Find(strHdr)
FindColumnHdrNum = rngAddress.Column '<--runtime error is caused by Nothing returned
End Function
Issue turns out to be a spurious line feed that was embedded in the header. It was strange as I kept re-typing it, but of course, I would always start at the "first letter" of the "comment" header, when in fact, the character preceded that. Thanks to all, for the help!
The name of your function is FindColHdrNum but you wrote this into the function:
FindColumnHdrNum = rngAddress.Column
Instead of:
FindColHdrNum = rngAddress.Column

How to use Match (and replace) function when the source you are matching with is a dynamic (textbox) value (in userforms)?

I am extremely new to vba code/coding of any sort, and am trying to develop a loaning system for equipment within my discipline using excel sheets and forms.
Essentially, I want a cmdbutton_click to update the availability status of the specific piece of equipment to "On Loan" within the inventory list spreadsheet. The problem I am having however, is with the fact that the form user will enter the ItemID (number) which obviously will always be different. The item ID is the value of which I am looking to use the Match function with.
I have tried to refer to the form's ItemID text box using the match function, but it does not work whatsoever - I understand this is probably completely incorrect.
Set ws2 = Worksheets("MajorInventoryList")
ws2.Cells(WorksheetFunction.Match(me.txtID.value), 10) = "On Loan"
This brings about the Compile error: 'Argument not optional'
Is there any way to ameliorate this?
Use Find like this:
Set ws2 = Worksheets("MajorInventoryList")
Set fnd = ws2.Range("A:A").Find(Me.txtID.Value)
If Not fnd Is Nothing Then ws2.Cells(fnd.Row,10).Value = "On Loan"
This will look for Text Input in Column A and if found, will place "On Loan" in column J of that row in which the value exists.

Error while copying more than 8202 characters from one cell to another

Problem - I have around more than 8202 characters in once cell say Range("A1").
Now I would like to copy the content of cell(A1) to cell(A2) using VBA. I'm using below Code
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1")
After the execution of the Code. It gives "Application Defined Or Object Defined Error !!"
Please help/assist with your expert comments.
Observation - If I reduce the length of "A1" cell to 8202 or less then about code works!
I'm Confused. Pls assist.
Change your code to
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1").Value
and it will work.
Not really sure why though, as .Value is the default property of a range.
I was able to duplicate your error with the following:
Sub Test8202Copy()
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim x As String
For i = 0 To 8202
x = x + "a"
Next i
wks.Range("A1").Value = x
wks.Range("A2") = wks.Range("A1")
End Sub
I was able to solve the error by adding .value to the copy.
Sub Test8202Copy()
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim x As String
For i = 0 To 8202
x = x + "a"
Next i
wks.Range("A1").Value = x
wks.Range("A2").Value = wks.Range("A1").Value
End Sub
Using an intermediate variable without the use of .Value seems to work:
Dim y As Variant
y = wks.Range("A1")
wks.Range("A2") = y
My guess so far is that 8202 exceed the character limit of the data type used when you don't define .Value. The in cell limit length is 32,767 (MS Excel 2010) which is almost 4x the 8201 value that clears.
#Chris Neilsen provided the most practical and elegant solution to the problem (his code snippet follows):
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1").Value
In order to investigate and understand the possible cause of this strange behavior (may be a bug) of the Range object, I've posted couple comments, which are summarized below:
There is a conceptual difference between the original expression (see below):
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1")
and solution proposed by #Chris Neilsen, namely: original expression is implicitly assigning the Range object var (essentially, a pointer) to another Range object, like demonstrated in the following code snippet with explicit assignment:
Set rng = Sheets("XYZ").Range("A1")
Sheets("XYZ").Range("A2") = rng
while proposed solution explicitly passes the value property. Still, the reason why assigning a Range object failed for a value with string.Length>8202 is currently unclear (it may be caused by some internal nuances of the Excel Range object implementation).
Many thanks for posting this interesting question and fruitful discussion.
Regards,
This limit (see below re excel-2007) is covered in this MSDN article although interestingly it implies a vba array is invoved
Separately as per https://stackoverflow.com/a/13665363/641067 excel-2003 cant handle array strings longer than 911 characters, whereas the article below references 1823 character
SYMPTOMS
When you run a Microsoft Visual Basic for Applications (VBA) macro to transfer data from a VBA array that contains strings of data to a range of cells in a Microsoft Excel worksheet, the data may be truncated (cut off).
Note In Microsoft Office Excel 2003 and in later versions of Excel, you may receive the following error message when you run the VBA macro in the Visual Basic Editor:
Run-time error '1004'
CAUSE
This problem may occur when one of the following conditions is true:
In Excel 2007, the VBA array is longer than 8,203 characters in length.
In Excel 2003 and in earlier versions of Excel, the VBA array is longer than 1,823 characters in length

Resources