Set Rng comes up as Nothing - excel

I would like some help on the below if you can.
I'm working between 2 workbooks and I want from the first one to find the value of Cell("B6") which happens to be a date on the second Workbook in column B. Although it seems that the code finds the date when it comes to set it as a range it comes as empty. Can you please help me to see what I'm doing wrong.
I'm a novice in VBA and I'm trying with an online search to make my life easier.
Thank you in advance.
Sub Update_Forecast_2()
Dim myFile As String
Dim YourFolderPath As Variant
Dim FindString As Date
Dim newFile As String
FindString = CLng(Date)
Dim Rng As Range
YourFolderPath = "C:\Users\konstand\Desktop\Forecast"
ChDir YourFolderPath
myFile = Application.GetOpenFilename
If myFile = "False" Then Exit Sub
Workbooks.Open Filename:=myFile
newFile = Replace(myFile, YourFolderPath + "\", "")
Range("B6").Select
Workbooks("Forecast file.xlsm").Activate
Sheets("Forecast_Sort").Activate
Range("A1").FormulaR1C1 = myFile
Workbooks(newFile).Activate
Range("B6").Activate
FindString = Workbooks(newFile).Sheets("Forecast").Range("B6").Value
'MsgBox FindString
If Trim(FindString) <> "" Then
With Workbooks("Forecast file").Sheets("Forecast_Sort").Range("B:B")
Set Rng = .Find(What:=DateValue(FindString), _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Rng.Select
End If
Workbooks("Forecast file.xlsm").Activate
End With
End If
End Sub
Following Erjon's request in order to help you more to understand what I'm trying to do I attached 2 pictures and kind of explained something. I hope I helped and didn't make it more confusing.
So I have the main file on which I want to see the changes
Main File
Then I have the file from which I want to take the updated values every week if not more frequently. Be aware that this file every time will have a different name, such as "Wk09Update.xlsx", "Wk10Update.xlsx", "Wk11Update.xlsx", .......
Though before I go to the new file to copy and paste the new values I want on the main file from the date that the new file starts to copy the values from columns H,I, & J and paste them on top of the existing values in columns C, D, & E. Then I want to go to the new file and copy/paste the updated values from there to columns H,I, & J on the main file so I can see the diffenerces from a week to week update.
New File(Wk11Update.xlsx)
How it should be after Wk12Update
What I'm trying to do
Object Variable or With block Variable not set

First of all you need to make your code simple for example you have a lot of .Activate.
This will for sure in some point lead you into confusion.
you have to declare first all your worksheets and workbooks like this:
Sub Test()
dim book1 as workbook 'a workbook
dim book2 as workbook 'another workbook
dim SheetOfBook1 as worksheet
dim SheetOfBook2 as worksheet
set book1 = workbooks("NameOfWorkbook1.xlsm")
set book2 = workbooks("NameOfWorkbook2.xlsm")
set SheetOfBook1 = book1.worksheets("NameOfSheet")
set SheetOfBook2 = book2.worksheets("NameOfSheet")
'at this point you can check everything you want without activating something for example
SheetOfBook1.range("A1") = SheetOfBook2.Range("A1") 'or whatever
'if you want to check if a value in book1 exists in book2 then do a loop
dim cell as range
for each cell in SheetOfBook2.Range("A1:A100).Cells
If SheetOfBook1.range("A1") = Cell.Value Then
msgbox "I founded what you are searching for"
End If
Next Cell
End Sub
So you have to eliminate all this .activate, use loops etc. As for your example can you edit your question and can you illustrate with an image what you want to achieve?
Edit
If you want to open workbooks based on weeknumber i have this following code:
Sub Test()
Dim Main As Workbook
Dim Update As Workbook
Dim ForecastSort As Worksheet
Dim Forecast As Worksheet
Dim CheckIfOpen
Dim WeekNumber As String
Dim FirstDayInWeek
Dim FirstDayOfWeekRow As Long
Dim lRowUpdate As Long
Set Main = Workbooks("Main.xlsm")
Set ForecastSort = Main.Worksheets("Forecast_Sort")
'The code below will open the workbook which for name has the number week of today date automatically----------------------------------------------
WeekNumber = WorksheetFunction.WeekNum(Date) + 1 'The requested week
CheckIfOpen = IsWorkBookOpen("C:\Users\Erjon-PC\Desktop\Forecast\Wk" &
WeekNumber & "Update.xlsx") 'Checks if the update workbook is opened or not
FirstDayInWeek = Date - Weekday(Date, vbUseSystem) + 2 'First day of requested week
FirstDayOfWeekRow = ForecastSort.Range("B:B").Find(FirstDayInWeek).Row 'Finds the row of the start day of the requested week in main book
If CheckIfOpen = True Then
Set Update = Workbooks("Wk" & WeekNumber & "Update.xlsx")
Else
Set Update = Workbooks.Open("C:\Users\Erjon-PC\Desktop\Forecast\Wk" & WeekNumber & "Update.xlsx")
End If
'---------------------------------------------------------------------------------------------------------------------------------------------------
Set Forecast = Update.Worksheets("Forecast")
lRowUpdate = Forecast.Cells(Forecast.Rows.Count, "W").End(xlUp).Row 'Last row in column W in update book
Forecast.Range("W2:Y" & lRowUpdate).Copy
ForecastSort.Range("H" & FirstDayOfWeekRow).PasteSpecial xlPasteValues
Update.Close savechanges:=False
End Sub
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
The above code will open the workbook that has the week number in it's name, today it will open Wk11Update.xlsx, the next week it will open Wk12Update.xlsx.
If you want to open books that has for name future dates just add +1 or more to this code:
WeekNumber = WorksheetFunction.WeekNum(Date) + 1 'The requested week
Then in the opened book it will find last row with data in the column W, it will copy 3 column starting from W, and paste them in the column H of main book. The data will be pasted in the row where the first day of requested week is.

Related

Attempting to Index Match Match using VBA and failing

I am attempting to identify the row and column of which the intersection is the data I want to retrieve, much like an index match match formula in Excel. My method is find the data in the column, get the column letter, and do the same with the data in the row and retrieve the row number. The problem I am having is that I have to reference a cell in a separate workbook where the macro is located to open another spreadsheet's name that changes with the month. I'm sure this whole thing's method is not very good, advice would be appreciated!
Option Explicit
Sub RevenueTest()
'GVS1 Revenue Index Match Test
'DELETES & COPIES GVS1 revenue into P&R File
Dim GVS1 As String
GVS1 = ThisWorkbook.Sheets("Revenue").Range("v13")
Dim GVS1IS As String
GVS1IS = ThisWorkbook.Sheets("Revenue").Range("V7")
Dim GVS1Open As String
GVS1Open = Excel.Workbooks.Open(GVS1)
Dim Row As String
Row = Range("B5:B25").Find("Generation").Select.ActiveCell.Row
Dim Month As String
Month = ThisWorkbook.Sheets("Revenue").Range("V4")
Dim MonthActual As String
MonthActual = Month & " Actual"
Dim Column As String
Column = Range("A1:P15").Find(MonthActual).Select.ActiveCell.Column
Dim GVS1RowAndColumn As String
GVS1RowAndColumn = Column & Row
'OPENS / Indexes and Copies Revenue
Excel.Workbooks.Open (GVS1)
Columns("C:Q").EntireColumn.Delete
Range(GVS1RowAndColumn).Copy
'PASTES GVS1 revenue into P&R File
Dim Revenue As Worksheet
Set Revenue = ThisWorkbook.Sheets("Revenue")
ThisWorkbook.Activate
Revenue.Range("D3:D11").Find("Revenue").Select
Selection.End(xlToRight).Select
ActiveCell.Offset(0, 1).Range("A1").PasteSpecial xlPasteValues
End Sub
I'm not sure if I properly understood this line
My method is find the data in the column, get the column letter, and do the same with the data in the row and retrieve the row number.
But I do have a similar index match function in my stock, take a look and modify it to your needs.
Option Explicit
Sub Return_value()
Dim Rmrks As Range, Itm_Rng As Range
Dim ItmLstPR As Range, ItmLstCode As Range
On Error Resume Next
With Application
.EnableEvents = False
.ScreenUpdating = False
'they are table range btw like, "tabe_name[column_name]"
'in this range the return value will be pasted
Set Rmrks = .Range("Pip_Line[Remarks]")
'this range has the key word that needs to be matched
Set Itm_Rng = .Range("Pip_Line[Item_Code]")
' from "DMY_Pip_Line[Remarks]" range matched value will be returned
Set ItmLstPR = .Range("DMY_Pip_Line[Remarks]")
'we use "DMY_Pip_Line[Item_Code]" to match our keyword from "Pip_Line[Item_Code]" range
Set ItmLstCode = .Range("DMY_Pip_Line[Item_Code]")
'Return Remarks
Call Match_Value(ItmLstPR, Itm_Rng, ItmLstCode, Rmrks)
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
you can insert above code in a worksheet or in a module.
Paste below code in a module to get the final result.
Option Explicit
Public Sub Match_Value(ByVal ReturnVal As Range, ByVal LookupVal As Range, ByVal LookupRng As Range, ByVal PasteRng As Range)
Dim rng As Range, ResultRow As Long, foundcell As Range, ColmnDist As Long, FoundVal As String
'find column offset
ColmnDist = ReturnVal.Column - LookupRng.Column
ResultRow = PasteRng.Column - LookupVal.Column
On Error Resume Next
For Each rng In LookupVal
'return due placing location row
Set foundcell = LookupRng.Find(rng.Value, LookIn:=xlValues, Lookat:=xlWhole, MatchCase:=True)
'return value
FoundVal = foundcell.Offset(0, ColmnDist).Value
If Not foundcell Is Nothing And FoundVal <> vbNullString Then
rng.Offset(0, ResultRow).Value = FoundVal
End If
Next
End Sub
In order to understand your code I have rearranged it. In order for you to understand your code I have commented it. To be clear: this is your code, unchanged! We just study.
Sub RevenueTest()
'GVS1 Revenue Index Match Test
'DELETES & COPIES GVS1 revenue into P&R File
Dim Revenue As Worksheet
Dim GVS1 As String
Dim GVS1IS As String
Dim GVS1Open As String
Dim Row As String ' "Row" is an Excel object
Dim Month As String
Dim MonthActual As String
Dim Column As String ' "Column" is an Excel object
Dim GVS1RowAndColumn As String
GVS1 = ThisWorkbook.Sheets("Revenue").Range("V13")
GVS1IS = ThisWorkbook.Sheets("Revenue").Range("V7")
GVS1Open = Excel.Workbooks.Open(GVS1) ' the workbook is an object: can't assign to String
' "ActiveCell.Row" is a number: why assign to a string variable?
' "Row" is an object: can't be the name of a variable
' don't select anything: create a range object instead
' "Find" returns a range object if successful
' if unsuccessful attempting to access that range must fail
' since you don't specify any sheet, 'Range("B5:B25")' is presumed
' to be on the ActiveSheet
Row = Range("B5:B25").Find("Generation").Select.ActiveCell.Row
Month = ThisWorkbook.Sheets("Revenue").Range("V4")
MonthActual = Month & " Actual"
Column = Range("A1:P15").Find(MonthActual).Select.ActiveCell.Column
GVS1RowAndColumn = Column & Row
'OPENS / Indexes and Copies Revenue
Excel.Workbooks.Open GVS1 ' don't enclose arguments in parentheses
Columns("C:Q").EntireColumn.Delete ' columns are in the ActiveSheet
Range(GVS1RowAndColumn).Copy ' Range is on the ActiveSheet
'PASTES GVS1 revenue into P&R File
Set Revenue = ThisWorkbook.Sheets("Revenue")
ThisWorkbook.Activate ' no need to activate anything
Revenue.Range("D3:D11").Find("Revenue").Select ' no need to select anything
Selection.End(xlToRight).Select '
ActiveCell.Offset(0, 1).Range("A1").PasteSpecial xlPasteValues
End Sub
Then I tried to re-write your code so that it might work. You can see how far I got. Look for the specification of the search ranges. They are on the ActiveSheet. Which is the ActiveSheet? We have no clue. But the code shows you how to approach the subject.
Sub RevenueTest_2()
Dim GVS1Book As Workbook
Dim Revenue As Worksheet
Dim Fnd As Range ' result of 'Find'
Dim R As Long ' a row number
Dim C As Long ' a column number
Dim GVS1 As String
Dim GVS1IS As String
Dim Month As String
Set Revenue = ThisWorkbook.Sheets("Revenue") ' use "Set" to assign an object to a variable
With Revenue
GVS1 = .Range("V13").Value ' { always specify the property you want
GVS1IS = .Range("V7").Value ' { here it's the Value
Month = .Range("V4").Value ' "Month" is a string (like "April", not 4)
End With
Set Fnd = ActiveSheet.Range("B5:B25").Find("Generation")
If Fnd Is Nothing Then
MsgBox """Generation"" not found."
Exit Sub
Else
R = Fnd.Row
End If
Set Fnd = ActiveSheet.Range("A1:P15").Find(Month & " Actual")
If Fnd Is Nothing Then
MsgBox """" & Month & " Actual"" not found."
Exit Sub
Else
C = Fnd.Column
End If
Set GVS1Book = Workbooks.Open(GVS1) ' GVS1 must be a path & name
End Sub
When the other workbook is opened I gave up. At that moment Excel will make that workbook the ActiveWorkbook and the sheet which was active when that workbook was saved will become the ActiveSheet. Your code immediately starts deleting columns on that unknown sheet. I couldn't get myself to do that.
As you complete the code I started, just remember that you don't need to activate the other workbook. Excel has done it for you and will give you back your original view when you close that book. Consider using Application.ScreenUpdating = False not to show the active sheet. You don't need to select any worksheet on which you want to delete columns. But you do need to specify the worksheets on which you take action. I have strong doubt that my code looks for the two search criteria on the correct sheet. I specified ActiveSheet because that's what your code implied. So we're probably both wrong :-)

Find columns with a specific headers that may be spelled differently

Good evening. I am developing a subroutine for a project whereby the user is able to upload specific data from a separate workbook into the master. The routine will search through the chosen excel file for specific column headers and only copy/paste those desired columns to the master sheet. This is my first coding project and I think I have the process mostly sorted, however there is one bit of functionality that is eluding me: The specific column titles are moderately similar no matter the workbook, except they may vary between full name and abbreviation. For example the title of the column may be "AZM" or it may be "Azimuth". Alternatively one column title may be "N/S", "Northing" or "NS". There will never be multiple of these titles, just the one in the format that the workbook creator decided to go with.
My current code does not currently account for that:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim wb As Workbook
Dim filename As String, colName As String
Dim LRow As Long, LCol As Long
Dim pColName As String, MyHead(1 To 8) As String
Dim sCell As Range, PRng As Range
Dim col As Long, pCol As Long
MsgBox "Ensure plan includes MD/INC/AZM/TVD/NS/EW/VS/DLS"
With Application.FileDialog(msoFileDialogOpen) 'Open file explorer
.AllowMultiSelect = False 'Only allow one file to be chosen
.Filters.Add "Excel Files", "*.xlsx; *.xlsm; *.xls; *.xlsb", 1 'Limit selection options to excel files
If .Show Then
filename = .SelectedItems(1) 'Assign file path to variable filename
Set wb = Workbooks.Open(filename:=filename) 'Set selected Excel file to variable wb
MyHead(1) = "MD"
MyHead(2) = "Inc"
MyHead(3) = "Azimuth"
MyHead(4) = "TVD"
MyHead(5) = "N/S"
MyHead(6) = "E/W"
MyHead(7) = "VS"
MyHead(8) = "DLS"
If Not IsEmpty(ThisWorkbook.Worksheets("5D-Lite").Range("M33")) Then
LRow = Cells(Rows.Count, 13).End(xlUp).Row 'Find the last row of data in column M from previous plan
LCol = Cells(LRow, Columns.Count).End(xlToLeft).Column 'Find the last column of data in the last row
ThisWorkbook.Worksheets("5D-Lite").Range("M33:" & Col_Letter(LCol) & LRow).ClearContents 'Clear the contents of the range determined by the Last functions
End If
With wb.Worksheets(1)
For i = LBound(MyHead) To UBound(MyHead)
Set sCell = .Range("A1:R50").Find(What:=MyHead(i), LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False) 'Search for the desired directional plan items in column headers
If Not sCell Is Nothing Then
col = sCell.Column 'Located item's column number
pCol = i + 12 'Column number in master workbook to paste in
colName = Split(.Cells(, col).Address, "$")(1) 'Located item's column letter
pColName = Split(.Cells(, pCol).Address, "$")(1) 'Column letter in master workbook to paste in
LRow = FindLastNumeric() 'Find the final row with numeric data
Set PRng = .Range(sCell.Address & ":" & colName & LRow) 'Set total data range of desired column
wb.Activate
wb.Worksheets(1).Range(PRng.Address).Copy ThisWorkbook.Worksheets("5D-Lite").Range(pColName & "32") 'Copy contents of selected file to the 5D sheet
End If
Next
Range("M32:T" & LRow + 33).NumberFormat = "0.00" 'Assigns numeric formatting to the pasted data range
wb.Close SaveChanges:=False
Set wb = Nothing
End With
Else
MsgBox "No Plan Selected"
End If
End With
Application.ScreenUpdating = True
End Sub
Is there any way to modify the .Find function or the MyHead(i) variables to account for multiple possible variations on the same header name? Thanks for any ideas.
It looks to me like you need prepare some kind of a dictionary. A simple solution would be to have an Excel table which stores all the information, which is stored in an array on startup (for quicker references) and then used to translate inputs to outputs. It could look something like this:
POSSIBLE_SOURCE VALID_NAME
appl apple
apple apple
orng orange
orange orange
To use this you would search the source files for matches in POSSIBLE_SOURCE column, find corresponding value in VALID_NAME column and use the latter for whatever you need to do with the input row.

Data being extracted to another worksheet is not correct

I have a "Data" worksheet that holds loads of data. It has 17 columns A-Q and in the G column is the date that is meant for dd/mm/yyyy. I have a separate worksheet called "NoEntry" and here is where I would like the dates to be entered by the user (Start-date L15 and End-date in L16) and once a button clicked all the data between and including the start and end date will go into another worksheet called "DateData".
The code I have below kind of works. The problem is that for some reason the data transferred over is not correct. Firstly, not all data keeps within the boundaries - some gets copied over with dates that are before the "start date". Another thing is that in the data there are blank records (A-F has data and onwards is blank) and some of them get copied over also - even though they have no date.
I feel like either its not looping correctly through all records or perhaps its a formatting issue. Perhaps is there a way to convert all the date column into a specific format before it does the copying - has to be dd/mm/yyyy. Or could just be something I'm missing?
from testing it seems only one record got through that is before the start date but blank data still gets copied over the date used was 16/09/2019 to 07/10/2019
Any help would be much appreciated,
Thanks :)
Private Sub CommandButton2_Click()
Application.ScreenUpdating = False
Dim wsData As Worksheet, wsDate As Worksheet, wsNoEntry As Worksheet
Dim dSDate As Date, dEDate As Date
Dim lRowStart As Long, lRowEnd As Long
Dim aData() As Variant
Dim i As Long
'set the worksheet objects
Set wsData = ThisWorkbook.Sheets("Data")
Set wsDate = ThisWorkbook.Sheets("DateData")
Set wsNoEntry = ThisWorkbook.Sheets("NoEntry")
'required variables
dSDate = wsNoEntry.Range("L15").Value
dEDate = wsNoEntry.Range("L16").Value
'set the array - you can make this dynamic!
aData = wsData.Range("A1:Z1000").Value
'for loop to find start
For i = 1 To 1000
If aData(i, 7) = dSDate Then
lRowStart = i
Debug.Print "Start row = " & lRowStart
Exit For
End If
Next i
'now loop backwards to find end date
For i = 1000 To 1 Step -1
If aData(i, 7) = dEDate Then
lRowEnd = i
Debug.Print "End row = " & lRowEnd
Exit For
End If
Next i
'now we have start and end dates
'going to use copy/ paste for simplicity
wsData.Range("A" & lRowStart, "Z" & lRowEnd).Copy
'paste in date sheet
wsDate.Range("A1").PasteSpecial Paste:=xlPasteValues
'clear clipboard
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Input
Output - blacked out due to private information (G5 date shouldn't be there and you can see blanks

Vlookup Syntax and user input issues

I'm trying to create a macro that compares two user in-putted worksheets then moves the differences to different sheets depending on why its different.
The code first asks for input of the newest data and opens that sheet. Then it asks for the location of the older data to compare with but doesn't open it. It adds the necessary sheets to copy to.
It then goes down a column cell by cell looking for the matching serial on the second work book (this is mainly to ensure that its comparing the correct data in-case formatting is off). Once it finds the matching serial it compares the second serial for both entry's and depending on if its different or new input into one of the sheets.
The main issue I'm having is with VLookup. It is having multiple errors 424, 1004 and Compile expression errors. I need a little guidance as to why its having these issues. I have searched and found a lot on needing to have brackets to reference a file but when I follow those formats exactly it throws the expression error.
Any advice is appreciated.
Sub Compare()
'Open workbooks
''Worksheet 1
Dim filter As String
Dim caption As String
Dim WB1FN As String
Dim WB1 As Workbook
filter = "Excel Sheets (*.xlsx),*.xlsx"
caption = "Please select newest equipment file"
MsgBox (caption)
WB1FN = Application.GetOpenFilename(filter, , caption)
If WB1FN = "False" Then
MsgBox "File not selected to import"
Exit Sub
End If
Set WB1 = Application.Workbooks.Open(WB1FN)
''Worksheet 2
Dim caption2 As String
Dim WB2FN As String
filter = "Excel Sheets (*.xlsx),*.xlsx"
caption2 = "Please select previous equipment file"
MsgBox (caption2)
WB2FN = Application.GetOpenFilename(filter, , caption)
If WB2FN = "False" Then
MsgBox "File not selected to import"
Exit Sub
End If
'Comparing data
''MS find and compare
Dim MS1 As String
Dim ESN1 As String
Dim ESN2 As String
Dim LastRow As Long
Dim i As Integer
Dim d As Integer
Dim n As Integer
Dim Filename As String
d = 4
n = 4
Set WB1 = ActiveWorkbook
'Create sheets
Sheets.Add(After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count)).Name = "A"
Sheets.Add(After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count)).Name = "B"
Sheets.Add(After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count)).Name = "C"
'Gets the last row number
ActiveWorkbook.Sheets(1).Activate
LastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
For i = 4 To LastRow
''Assigning MS1,ES1,ES2
MS1 = Cells(i, 6)
ESN1 = Cells(i, 15)
ESN2 = Application.WorksheetFunction.VLookup(MS1, '[" & WB2FN & "]Sheet1'! [R3C6:R10000C15], 10, False)
''Compare ESN and copy data
If ESN2 <> ESN1 Then
cell.EntireRow.Copy Sheets(2).Cells(d, 1)
n = d + 1
ElseIf Application.WorksheetFunction.IsNA(ESN2) = "TRUE" Then
cell.EntireRow.Copy Sheets(4).Cells(n, 1)
n = n + 1
End If
Next i
'X find and copy
Dim OEM As String
ActiveWorkbook.Sheets(2).Activate
LastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
n = 3
i = 3
For i = 3 To LastRow
''Check for X
OEM = Cells(i, 4)
If OEM = "x" Then
cell.EntireRow.Copy Sheets(3).Cells(n, 1)
n = n + 1
End If
Next i
MsgBox "Compare successful"
End Sub
have brackets to reference a file You can only use that approach if you are assigning a formula to a cell or range.
Example:
Dim myformula As String
myformula = "=VLOOKUP(" & MS1 & _
",'[" & WB2FN & "]Sheet1'! [R3C6:R10000C15], 10, False)"
Range("A1").Formula = myformula
But if you use VBA Worksheet Function, you need to somehow access the database or table you are fetching data from at runtime. Meaning you have to pass objects on the arguments and not strings as you do in above.
Something like:
'~~> the rest of your code before Vlookup here
Dim wb As Workbook
Dim mytable As Range
Set wb = Workbooks.Open(WN2FN, , True) '~~> read only, avoid errors when file in use
Set mytable = wb.Sheets("Sheet1").Range("F3:O10000")
On Error Resume Next '~~> to handle when Vlookup returns #N/A or errors out
ESN2 = Application.WorksheetFunction.VLookup(MS1, mytable, 5, 0)
If Err.Number <> 0 Then myvalue = CVErr(xlErrNA)
On Error GoTo 0 '~~> reset error handling to trap other errors
Debug.Print ESN2
I just provided the part where you use the Vlookup WorksheetFunction. You can use the rest of your code before it. Basically above code:
assigns source table to variable and passed it directly to Vlookup arguments.
Uses Vlookup via VBA WorksheetFunction to fetch data.
Take note of the OERN (On Error Resume Next) routine and OEG0 (On Error Goto 0).
In VBA when a Worksheet Function returns an error (eg. #N/A for Vlookup), the code errors out and stops execution. There is no IFERROR like we have in worksheet formulas. So you need to handle it using error handling routines.
Also take note that it is better to fully qualify the objects you're working on.
This is a good place to start to optimize your codes and avoid runtime errors.

Excel VBA loop Column, search for str, on find open workbook, copy range of cells

i have a little problem. I work in product development and manage 100+ projects a year, the runtime of an given project is fluid, some take longer then planed to finish and others are quicker. For every project a time/cost workbook is setup with planed costs/time and then once the project is done the actual costs/time are imputed. Up until now every table has been manualy created, filled out and saved to a folder, the files are never named the same and end up with the different title formats. This makes reviewing the yearly average cost/runtime of projects very hard.
The idea is to make the creation of the time/cost workbooks simpler.
The Workflow:
Open Workbook "Projects"
Enter Project-Nr.: xxx-yyyy-zz in Column A
(xxx = Project-Nr. | yyyy = year | zz = Project-type)
Enter Project-Name in Column B
Select Row with Project hit Button"Create_Open"
New Workbook is created using template
Project-Nr. and Project-Name are copied into Template
Workbook is saved with filename (Project-Nr. "_" Project-Name ".xml")
That part was simple enough, code bellow, it doesn't look very nice but it gets the job done.
Function FileExists(FullFileName As String) As Boolean
'returns TRUE if the file exists
FileExists = Len(Dir(FullFileName)) > 0
End Function
Sub Create_Workbook()
Dim selRow As Integer
Dim file_path As String
Dim file_extension As String
file_path = "...dir" ' Speicherpfad festlegen
file_extension = ".xls" ' Speichermedium festlegen
selRow = ActiveCell.Row 'aktive Zeile finden
If Range("A" & selRow) = "" Then ' prüfen ob Zeile ein Projekt enthält
MsgBox ("Bitte eine ausgefullte Zeile auswählen")
End
End If
project_nr = Mid(Range("A" & selRow), 1, 11) ' zuweisen Projekt-Nr.
project_be = Mid(Range("B" & selRow), 1, 100) ' zuweisen Projekt Bezeichnung
'If Workbook Exists Open if not Create and write to Workbook
If Not FileExists(file_path & project_nr & "_" & project_be & file_extension) Then
'Workbook null setzen und Template laden
Set new_workbook = Nothing 'null setzen
Set new_workbook = Workbooks.Add(Template:="dir") 'Postfach laufwerk einstellen
'Projekt-Nr. und Projektbezeichnung in Controllingblatt speichern
Range("C1") = project_be 'Projektbezeichnung setzen
Range("C2") = project_nr 'Projektnummer setzen
Range("C3") = Format(Date, "mm-dd-yyyy") 'Heutiges Datum setzen
'Workbook speichern "Projekt-Nr._Projektbezeichnung"
new_workbook.SaveAs Filename:=file_path & project_nr & "_" & project_be & file_extension
Else
Workbooks.Open file_path & project_nr & "_" & project_be & file_extension
End If
End Sub
Now comes the part im having the mother of all problems solving. Search for a year in Column A, once a Project is found thats from teh given year the coresponding workbook is opened. A range of cells is copied from the opened Workbook to a new worksheet in the Project list Workbook. The range of Cells is pasted into the the new Worksheet thats given the name of the searched year. The search loops through all Rows of Column A until it reaches an empty Row.
Workflow:
Buttonclick opens Userwindow "Input year"
Clicking OK button without year input returns error
Input year cick OK button
Create new Worksheet with title of input year
Column A is searched for the Year.
Once a Project is found from the coresponding year that Project Workbook is opened
Copy a range of cells form Workbook
Paste the range of cells to Project list Workbook in the worksheet from step 4
close workbook opened in step 6
Loop 5-9 until emty cell
What i have so far isn't much at all(code bellow), i have come up against a solid wall.
I'm wondering if anyone could help me out, or if my logic is totaly flawed and i should start from scratch and build the system up differently.
Private Sub cmdOK_Click()
If Len(Me.TextBox1 & "") = 0 Then ' prüfen ob Zeile ein Projekt enthält
MsgBox ("Bitte Jahr eingeben")
Else
'Loop through cells on a sheet to find strFind1
End If
End Sub
Any help is much appreciated.
hope this helps. I tried a test and I think I got it pretty close to your question. I have a projectList workbook, on sheet one I have the following values in column A
111-2010-222
222-2010-333
333-2010-144
444-2011-111
555-2011-222
Then I have a button named sumProjects and in cell D2 I have the year I want to total. For each of the project names above I created a spreadsheet named the same, and in those spreadsheets I put some data in column D. Then in the click even for the sumProjects button I put this code
Private Sub CommandButton1_Click()
Dim lngLR As Long
Dim wb As Workbook
Dim sh, sourceSheet As Worksheet
Dim i, x as Integer
With Me
lngLR = .Cells(.Rows.Count, "A").End(xlUp).Row 'finds the last row of column A
End With
'creates a new worksheet with the name of the given year
With ThisWorkbook
Set sh = .Worksheets.Add(after:=.Sheets(.Sheets.Count))
sh.Name = (Range("D2").Value)
End With
x = 1 'this will be used to keep track if which row to input
'data on the destination sheet, we set it to 1 because
'we know the destination sheet is a new sheet so we know
'where the first row is, we do not have to calculate it
'loops through all of the project names in column A
'looking for one that contains the year given in D2
For i = 1 To lngLR
'look for year in project name
If InStr(Range("A" & i), Range("D2")) Then
'project of given year found. Open workbook and get data
Set wb = Application.Workbooks.Open("C:\Desktop\" & Range("A" & i) & ".xlsx")
Set sourceSheet = wb.Worksheets(1)
sh.Range("C" & x).Value = sourceSheet.Range("D5").Value
x = x + 1 'x is only incremented when a value is placed on the new sheet
wb.Close
End If
Next i
End Sub
So i edited loveforvdubs code to fit my needs. Im sure the copying of the Worksheet template could have been solved much more elegantly, but i couldn't get any of the other solutions to stick.
Thanks again for the help loveforvdubs!
Private Sub CommandButton1_Click()
Dim lngLR As Long
Dim wb As Workbook
Dim sh, sourceSheet As Worksheet
If Len(Me.TextBox1 & "") = 0 Then ' If TextBox1 is empty returns Msg
MsgBox ("Bitte Jahr eingeben")
Else
With Me
lngLR = .Cells(.Rows.Count, "A").End(xlUp).Row 'finds the last row of column A
End With
'creates a new worksheet with the name of the given year
With ThisWorkbook
Worksheets("Auswertung").Visible = True
Worksheets("Auswertung").Select
Worksheets("Auswertung").Copy After:=Sheets(1)
Worksheets("Auswertung (2)").Select
Worksheets("Auswertung (2)").Name = TextBox1
Worksheets("Auswertung").Visible = False
Set sh = Worksheets(2)
End With
'loops through all of the project names in column A
'looking for one that contains the year given in TextBox1
For i = 1 To lngLR
'look for year in project name
If InStr(Range("A" & i), TextBox1) Then
'project of given year found. Open workbook and get data
Set wb = Application.Workbooks.Open("K:\Projektplanung\Projektkosten\" & Range("A" & i) & "_" & Range("B" & i) & ".xlsx")
Set sourceSheet = wb.Worksheets(1)
sh.Range("A" & i).Value = sourceSheet.Range("I30").Value
wb.Close
End If
Next i
End If
End Sub

Resources