I have a sheet with a list of course names called Matrix. In another sheet named Courses Date I will have the same courses with the date they were taken.
Example:
The course named Safety Driving will be in Matrix on row 1. In Courses Date there is data from E1:BF1 with the same name. If courses need a refreshment there will be another column named exactly the same name of the course + Refresher (Safety Driving Refresher).
What I am trying to do is to find if a course has a refresher or not. My code returns Run-time error '91': Object variable or With block variable not set if nothing is found.
This is my code:
RefresherColNumber = Range("'Courses Date'!E1:BF1").Find(Range("'Matrix'!" & courseColLetter & "1").Value & " Refresher").Column
Add a check
Dim refreshRange As Range
Set refreshRange = Range("'Courses Date'!E1:BF1").Find(Range("'Matrix'!" & courseColLetter & "1").Value & " Refresher")
If Not refreshRange Is Nothing Then RefresherColNumber = refreshRange.Column
You could use Application.Match to test, with IsError, if value found in row and add 4 to where found to get the column. You should qualify your ranges with the parent worksheet object as well to avoid bugs with implicit activesheet referencing.
Dim matchValue As Variant
matchValue = Application.Match(Range("'Matrix'!" & courseColLetter & "1").Value & " Refresher", Range("'Courses Date'!E1:BF1"), 0)
If Not IsError(matchValue) Then RefresherColNumber = matchValue + 4
Related
the ones who read this topic, this is my first question at StackOverflow if any mistakes were made by me please forgive me, I would appreciate it if someone helps.
I have a table which is declared 'genTable' as ListObject. In order to insert and get data from each column of the table. I just set ranges like as:
Dim genTable As ListObject
Set genTable = test.ListObjects("hourly_data")
Set u1_NetLoad = genTable.ListColumns("U1 Net Load").DataBodyRange
I used the following code and helped me setting ranges however it did not satisfied me. I want to learn more dynamic method for my knowledge of programming.
For Each word In genTable.HeaderRowRange
i = 1 + i
test.Cells(22 + i, 2).value = "Set " & Replace(CStr(word), " ", "") & _
" = genTable.ListColumns(" & Chr(34) & word & Chr(34) & ").DataBodyRange"
Next
the output of this code is copied to VBA module to set ranges.
Actually, my scripts work pretty well, but I just want to know If can I set ranges more easily and depending on variables. For my case, I typed every single ranges. I tried the 'for each' loop like this but it did not work.
For Each word In genTable.HeaderRowRange
range_name = Replace(CStr(word), " ", "") & "_"
Set range_name = genTable.ListColumns(word).DataBodyRange
Next
The code above does not work, is there anyway to make it works?
Thanks for reading.
I had the same question last week, I did some digging and came up with this.
Fist I define array then reDim with the the lower and upper limits of the array.
Then using the loop, populated each array entry with the sheet and range needed, noting I needed to use the sheet number, not the name, then I could populate the whole array, then proceed with the code:
...
Dim Nbr_Students As Integer
Dim Counter As Integer
Dim i As Integer
Dim Student_Sheets As Variant
Nbr_Students = Sheets("Master Lists").Range("M3").Value - 1
Counter = 15
i = 0
ReDim RngArray(0 To Nbr_Students)
Do While i <= Nbr_Students
Set RngArray(i) = Worksheets(Counter).Range("C141:C157")
Counter = Counter + 1
i = i + 1
Loop
...
Original Post: Link
I am trying to create a VBA code that will pull the info to the Left (eventually the right) of a Hyphen based on a range and a cell given by the user.
EX:
Result A & Result B are what I am trying to get too.
I've tested everything in my code until this part and it all works. The entire thing works if I physically type in a cell address (i.e $D2 - I will need the column absolute, but the row relative so that it moves with the range selection). I just can't get it to work with the user input of the "Starting" variable. I need it to be user input because this code will be used on sheets set up completely different than this one. There is a good chance I am missing something obvious but I'm not seeing it #_#. Any suggestions?
**Sorry in advance for the long lines of code
Private Sub Seperate_XtoY_Click()
Dim iCol As Long
Dim iCount As Long
Dim i As Long
Dim Smaller As Range
Dim Bigger As Range
Dim Starting As Range
'Get number of columns that you want to insert with a user input box
iCount = InputBox(Prompt:="How many columns you want to add?")
'Get column NUMBER where you want to insert the new column
iCol = InputBox _
(Prompt:= _
"BEFORE which column do you want to add the new column(s)? (Enter the column number i.e A=1, B=2, C=3, etc)")
'loop to insert new column(s)
For i = 1 To iCount
Columns(iCol).EntireColumn.Insert
Next i
'Makes range variable "Starting" equal to the user input of a range (in this case just 1 cell)
Set Starting = Application.InputBox("Select the FIRST cell of the Original Range of #'s", "Obtain Range Object", Type:=8)
'Makes range variable "Smaller" equal to the user input of a range (where the info will actually populate)
Set Smaller = Application.InputBox("Select a range", "Obtain Range Object", Type:=8)
Smaller.Formula = "=IF(ISNUMBER(SEARCH(""½"", & Starting.Address(0, ""$"") &)),""0.5"",IF(ISNUMBER(SEARCH(""¼"",& Starting.Address(0, ""$"") &)),""0.25"",IF(ISNUMBER(SEARCH(""¾"",& Starting.Address(0, ""$"") &)),""0.75"",LEFT( &Starting.Address(0, ""$"")&, FIND(""–"",& Starting.Address(0, ""$"")&)-1))))"
End Sub
It turns out I had the right idea based on my last comment. I did need remove the variable completely out of the quotes (and then restart them), double check the placing of where I put those quotes, and use a different version of the .Address function to make only my column an absolute reference. All the other lines of code from above were all good, it was just the final line that needed to changed. Thank you #BigBen for giving me a push in the right direction. Looking at the program with fresh eyes also helped lol.
Smaller.Formula = "=IF(ISNUMBER(SEARCH(""½""," & Starting.Address(RowAbsolute:=False) & " )),""0.5"",IF(ISNUMBER(SEARCH(""¼"", " & Starting.Address(RowAbsolute:=False) & ")),""0.25"",IF(ISNUMBER(SEARCH(""¾"", " & Starting.Address(RowAbsolute:=False) & " )),""0.75"",LEFT( " & Starting.Address(RowAbsolute:=False) & " , FIND(""–"", " & Starting.Address(RowAbsolute:=False) & ")-1))))"
I also got the Right side function working too if anyone is interested:
Bigger.Formula = "=IF(ISNUMBER(SEARCH(""– ½""," & Starting.Address(RowAbsolute:=False) & ")),""0.5"",IF(ISNUMBER(SEARCH(""– ¼""," & Starting.Address(RowAbsolute:=False) & ")),""0.25"",IF(ISNUMBER(SEARCH(""– ¾""," & Starting.Address(RowAbsolute:=False) & ")),""0.75"",RIGHT(" & Starting.Address(RowAbsolute:=False) & ",LEN(" & Starting.Address(RowAbsolute:=False) & ")-FIND(""– ""," & Starting.Address(RowAbsolute:=False) & ")-1))))"
PLEASE NOTE for anyone who may want to use a variation of my code I used a slightly bigger hyphen than the typical hyphen ("-" vs "–")
Evaluate is throwing error 2029 (#NAME).
The project is using Census procedures to allocate seats in the House of Representatives for any given number of house members (currently 435). There are a number of proposals to expand the size of the House. I'm investigating budget and economic implications.
My workbook has a sheet named PVC. I'm trying to find the maximum value in column E (number of seats allocated to a given state) for a value in column C (two-letter state abbreviations).
I have removed quite a few lines.
I have experimented with a user-defined function MaxIf().
Sub CountSeatsEval()
Dim lNoSeats, lG2, lastrow, lStateRow, lStateSeats, lStateNo As Long
Dim sFileName, sPathName, sFunction, sSearchValue, sSearchState As String
Dim sStateAbbr, vStateSeats As Variant
Dim wsSource, wsTarget As Worksheet
Dim rMaxRange, rSearchValue, rSearchState As Range
Dim rLookup1 As Range
Set wsSource = ThisWorkbook.Worksheets("PVC")
'Following line is to make life easy temporarily
Set wsTarget = ThisWorkbook.Worksheets("PVC")
lNoSeats = wsSource.Range("G2").Value
...
'Copy and paste G2 to replace formula with value
wsTarget.Range("G2").Copy
wsTarget.Range("G2").PasteSpecial (xlPasteValues)
lastrow = wsTarget.Cells(Rows.Count, 6).End(xlUp).Row
...
sSearchValue = "'PVC'!E2:$E$" & lastrow
sSearchState = "'PVC'!$C$6"
...
sStateAbbr = "CA"
lStateRow = 6
vStateSeats = Evaluate("IF((MAXIFS(sSearchValue, sSearchState, sSearchState))>0,(MAXIFS(sSearchValue, sSearchState, sSearchState)),1)")
End Sub
sSearchValue and sSearchState are VBA local variables:
Dim sFileName, sPathName, sFunction, sSearchValue, sSearchState As String
Note that this statement declares sSearchState as a String, and then leaves all other 4 variables without a declared type, making them implicit Variant variables (see VariableTypeNotDeclared Rubberduck inspection details).
Being local VBA variables, they live in the VBA runtime context, and Excel doesn't have the slightest idea about their existence - so you get a #NAME? error:
In Excel you get a #NAME? error whenever you try to evaluate a formula that contains a name that Excel cannot resolve in the current context.
So you need to have VBA evaluate the variables' values before you send the resulting expression over to Excel's calculation engine; you can do this by splitting up the string and using the concatenation operator (&):
vStateSeats = wsTarget.Evaluate("IF((MAXIFS(" & sSearchValue & "," & sSearchState & "," & sSearchState & "))>0,(MAXIFS(" & sSearchValue & "," & sSearchState & "," & sSearchState & ")),1)")
Unqualified, Evaluate will invoke [_Global].Evaluate, which is essentially Application.Evaluate, which may or may not produce the desired results - by qualifying it with a specific Worksheet object, the formula evaluates in the context of that worksheet.
I have a userform which is supposed to update different sheets according to combobox "(Select layer to update)" at a time, see attached image, as soon as I press on SAVA DATA button it return error. "Run time error 380" here are my codes. The listbox is supposed to update according the sheet selected under combobox "(Select layer to update)"
.ListBox1.ColumnCount = 28
.ListBox1.ColumnHeads = True
.ListBox1.ColumnWidths = "30,50,40,40,35,43,43,28,25,25,25,25,37,50,45,55,70,60,47,35,35,40,40,40,40,50,160,40"
If iRow > 1 Then
.ListBox1.RowSource = "ActiveSheet!A9:AB" & iRow
Else
.ListBox1.RowSource = "ActiveSheet!A9:AB9"
End If
End With
The RowSource property requires to assign a string reference prefixed by
the actual literal worksheetname plus an exclamation mark (e.g. Sheet1!A9:AB9),
not by characters starting with "ActiveSheet" as presumably there won't be a sheet named
"ActiveSheet".
If you want to use VBA's ActiveSheet property as first part
you could use the following way getting the sheet's address passing the additional
External:=True argument (attention to :=) which returns the fully qualified sheet name as string:
.RowSource = ActiveSheet.Range("A9:AB" & iRow).Address (External:=True)
Another way would be to simply join the string parts via the ampersand connector &,
e.g.
ActiveSheet.Name & "!A9:AB" & iRow (using the name of ANY active sheet) or
ThisWorkbook.Worksheets("Sheet1").Name & "!A9:AB" & iRow (using the tabular sheet name) or
Sheet1.Name & "!A9:AB" & iRow (using the CodeName)
I'm working on problem that necessitates the use of nested formulas in excel. For eg:
I have a column for errors and one for its analysis
Error Analysis
Enter a valid material number Invalid Material
Eg errors:
Enter a valid material number; The material number 1234 does not
exist.
PO number XYZ does not exist.
VIN number 123 does not exist.
Country of origin AB does not exist.
I have a compendium of such errors and their analyis in the next sheet, and I'm using VLOOKUP in conjuction with FIND to lookup the analysis for the known errors.
=VLOOKUP(LEFT(F2, FIND(" ", F2, FIND(" ", F2) + 1) - 1)&"*", 'Sheet2'!A:B, 2, 0)
What i'm trying to do here is extract the first two words from the error and append a * to it and use it in VLOOKUP.
It would be something like Vlookup "PO number *" in the other sheet and get the analysis for it. Asterisk is because I don 't get the same number daily. And I also know that the extracted first two words of the error will be unique. (I know that error with "Enter a" as the first two words will not appear again).
Now I get errors in the same column so I thought of making a button and writing a code which uses the above formula.
I tried to modify some code off the net, but I'm not getting anywhere with it. I'm totally new to VBA. It'd be great if you can provide a snippet for this. I'll try to replicate the procedure for other needs.
This code seems to be working for now
Sub PopulateAnalysis()
Dim an_row As Long
Dim an_clm As Long
Dim lft As String
Dim st_num As Integer
Dim fin As String
Dim searchStr As String
Dim soughtStr As String
Table1 = Sheet1.Range("F2:F6") 'ErrorColumn from Error table (How do I make the range dynamic??)
Table2 = Sheet5.Range("A1:B6")
an_row = Sheet1.Range("G2").Row ' Populate this column from the analysis table on sheet2
an_clm = Sheet1.Range("G2").Column
For Each cl In Table1
'How do I translate the above formula into VBA statements??
st_num = InStr(InStr(cl, " ") + 1, cl, " ")
lft = left(cl, st_num - 1)
fin = lft & "*"
Sheet1.Cells(an_row, an_clm) = Application.WorksheetFunction.VLookup(fin, Table2, 2, True)
an_row = an_row + 1
Next cl
MsgBox "Done"
End Sub
This should work. You don't need the debug lines of course ;)
Sub PopulateAnalysis()
Dim rngTableWithErrors As Range
Dim rngTableWithAnalysis As Range
Application.ScreenUpdating = False
'set the range for Table with error, Table1 on sheet 1
With Sheets(1) 'change to name of the sheet, more reliable than index num.
Set rngTableWithErrors = .Range("F2:F" & .Cells(.Rows.Count, 6).End(xlUp).Row)
Debug.Print rngTableWithErrors.Address
End With
'set the range for Table with Analysis, Table 2 on sheet 2
With Sheets(2) 'change to name of the sheet, more reliable than index num.
Set rngTableWithAnalysis = .Range("A1:B" & .Cells(.Rows.Count, 2).End(xlUp).Row)
Debug.Print rngTableWithAnalysis.Address
End With
'formula for cell G2
'=VLOOKUP(LEFT(F2;FIND(" ";F2;FIND(" ";F2)+1)- 1)&"*";Sheet2!A1:B23;2; 0)
rngTableWithErrors.Offset(0, 1).FormulaR1C1 = _
"=VLOOKUP(LEFT(R[0]C[-1],FIND("" "",R[0]C[-1],FIND("" "",R[0]C[-1])+1)-1)& ""*"",Sheet2!R1C1:R" & rngTableWithAnalysis.Rows.Count & "C2,2, 0)"
Application.ScreenUpdating = True
MsgBox "Done"
End Sub
Notes
You can notice, that we are setting the upper left cells of ranges manually. It's better practice to somehow find the upper left cells (using Find method is my favorite) and work from there. You never know, how the user will change the worksheet - i.e. add new rows, columns etc.