I have a task where I have two workbooks, one source and one destination. The task is to search a column in the destination workbook for a value that contains a certain string. When found, I have to search the source workbook in a certain column to find a matching string. I then take values from 2 other columns in that same row in the source workbook, combine them, and write them to a cell in the destination workbook.
The issue is that the values are being written to the wrong rows in the destination workbook, like this:
example1Broken
When it should look like this:
example2proper
Here is my current vba:
Sub CombineWorkbooks()
Dim var As Variant
Dim col As Variant
Dim i As Long
Dim Cell As Range
Dim wbSource As Workbook
Set wbSource = Workbooks.Open(Filename:="CopyFromWorkbookSource.xlsx", UpdateLinks:=3)
Dim wbDest As Workbook
Set wbDest = Workbooks.Open(Filename:="CopyFromWorkbookDest.xlsm", UpdateLinks:=3)
Dim address As Variant
Dim newAddressRow As Variant
Dim sourceVal1 As Variant
Dim sourceVal2 As Variant
'Dest wb number column that contains the search query
Dim sourceCol As Integer
sourceCol = 1
wbDest.Activate
'col = Split(ActiveCell(1).address(1, 0), "$")(0)
For i = 1 To Rows.Count
var = Cells(i, sourceCol).Value
If var Like "*WI*" And Not IsEmpty(Cells(i, sourceCol).Value) Then
wbSource.Activate
Set Cell = Nothing
Set Cell = Selection.Find(What:=var, LookIn:=xlValues)
If Cell Is Nothing Then
' MsgBox "Nothing"
Else
'We found a match!
MsgBox "Found hit for " & var & ": " & Cell.address
'This is where the value was found in the source workbook
address = Cell.address
'This is where the new value must go in the dest workbook NOTE the column letter must change!
newAddressRow = Split(address, "$A$")(1)
'Get the cell values from the source wb
sourceVal1 = Cells(newAddressRow, 2)
sourceVal2 = Cells(newAddressRow, 3)
MsgBox "SourceVal1: " & sourceVal1 & " SourceVal2: " & sourceVal2 & " Newaddressrow: " & newAddressRow & " i: " & i
'Activate the dest workbook for pasting
wbDest.Activate
'Write the source wb values into a single cell in the dest wb
Cells(i, 2).Value = sourceVal1 & Chr(10) & sourceVal2
End If
End If
Next i
End Sub
Consider removing the address variable and set the sourceVals using the found Cell's Row parameter. Also consider direct referencing workbooks and sheets instead of activating; see below.
Sub CombineWorkbooks()
Dim i As Long
Dim Cell As Range
Dim wbSource As Workbook
Dim wbDest As Workbook
Dim sourceCol As Integer 'Destwb number column that contains the search query
Set wbSource = Workbooks.Open(Filename:="CopyFromWorkbookSource.xlsx", UpdateLinks:=3)
Set wbDest = Workbooks.Open(Filename:="CopyFromWorkbookDest.xlsm", UpdateLinks:=3)
sourceCol = 1
' start at 2 to dodge the header
For i = 2 To wbDest.Sheets(1).Rows.Count
'this conditional can be removed if all non-header rows will contain WI
If wbDest.Sheets(1).Cells(i, sourceCol).Value Like "*WI*" Then
Set Cell = wbSource.Sheets(1).UsedRange.Find(What:=wbDest.Sheets(1).Cells(i, sourceCol).Value, LookIn:=xlValues)
If Not Cell Is Nothing Then
'We found a match!
'Write the source wb values into a single cell in the dest wb
Cells(i, 2).Value = wbSource.Sheets(1).Cells(Cell.Row, 2) & Chr(10) & wbSource.Sheets(1).Cells(Cell.Row, 3)
End If
End If
Next i
End Sub
Related
I am trying to run the Find method between two ranges in two different workbooks - If a value in the second range isn't found in the first range, then the data in the entire row to which the aforesaid cell belongs to should be copied from the second workbook and pasted in the first workbook. Each time I try to run my code I get runtime error #438 - Object doesn't support this property or method:
Option Explicit
Sub Data_Transfer()
Dim FileToOpen As Variant
Dim FileCount As Byte, SheetCount As Byte, SheetFound As Byte
Dim SelectedBook As Workbook
Dim WkSh As Worksheet
Dim Cell As Range, ChosenCell As Range, LookInRange As Range, LookAtRange As Range
FileToOpen = Application.GetOpenFilename(Title:="Select Files to Import Data", FileFilter:="Excel Files(*.xls*), *.xls*", MultiSelect:=True)
If IsArray(FileToOpen) Then 'Allows the user to click on the 'Cancel' button without it leading to an error
For FileCount = 1 To UBound(FileToOpen)
Set SelectedBook = Workbooks.Open(FileToOpen(FileCount))
'If a worksheet already exists for the month:
For SheetCount = 1 To ThisWorkbook.Worksheets.Count
If ThisWorkbook.Worksheets(SheetCount).Name = VBA.Replace(SelectedBook.Name, ".xls", "") Then
SheetFound = 1
Set WkSh = ThisWorkbook.Worksheets(SheetCount)
WkSh.Activate
MsgBox "A worksheet already exists for the selected month."
'Check if there are any expenses missing for the month:
Set LookInRange = ThisWorkbook.ActiveSheet.Range("C2:C" & Range("C2").End(xlDown).Row)
Set LookAtRange = SelectedBook.ActiveSheet.Range("C23:C" & Range("C2").End(xlDown).Row)
For Each Cell In LookAtRange
Set ChosenCell = LookAtRange.Find(LookInRange.Cell, , xlValues, xlWhole)
If ChosenCell Is Nothing Then
ChosenCell.EntireRow.Copy WkSh.Range("A" & Range("A1").End(xlDown).Row + 1)
End If
Next Cell
End If
If SheetFound = 1 Then: Exit Sub
Next SheetCount
'If a worksheet does not exist for the month:
With ThisWorkbook
.Worksheets.Add After:=Sheet11
.ActiveSheet.Name = VBA.Replace(SelectedBook.Name, ".xls", "")
SelectedBook.Worksheets(1).Range("A23").CurrentRegion.Copy .ActiveSheet.Range("A1")
SelectedBook.Close
For Each Cell In .ActiveSheet.Range("A1:A" & Range("A" & Rows.Count).End(xlUp).Row)
If VBA.Left(Cell.Value, 1) = "*" Then
Cell.EntireRow.Delete
End If
Next Cell
.ActiveSheet.Columns.AutoFit
End With
Next FileCount
End If
End Sub
Always specify for all Range, Cells, Rows and Columns objects in which workbook and worksheet they are.
If you don't do that for example like here:
Set LookAtRange = SelectedBook.ActiveSheet.Range("C23:C" & Range("C2").End(xlDown).Row)
Then the first Range is in SelectedBook.ActiveSheet but the second may be or may be not! As long it is not defined you don't know:
Set LookAtRange = SelectedBook.ActiveSheet.Range("C23:C" & SelectedBook.ActiveSheet.Range("C2").End(xlDown).Row)
So make clear that Range, Cells, Rows and Columns objects are always fully referenced to a workbook/worksheet.
I have the situation presented below in the image (Workbook 1):
and below (Workbook 2)
I want to copy my record from workbook 1 to workbook 2 if
in the Workbook 1 column A the string "surveyor" appears
the value from column B, which is exactly in the same row, where the string "suveyor" was found.
Then I would like to copy this value to my workbook 2.
I have prepared the code like this:
Sub FrontsheetAdd3()
Dim x As Worksheet, y As Worksheet, sPath As String
Dim i As Long
sPath = ThisWorkbook.Path & "\Survey_form.csv"
Set x = Workbooks.Open(sPath)
Set y = ActiveWorkbook.Sheets("Frontsheet") 'set to current worksheet name
'Name of the sheet is the same as Name of the workbook 1
If x.Sheets("Survey_form").Range("A" & i).Value = "surveyor" Then
x.Sheets("Survey_form").Rage("B" & i).Value = ("A" & i)
y.Sheets("Frontsheet").Range("D34").PasteSpecial
End If
Next i
End Sub
I have an error:
Method or data member not found
at the line
If x.Sheets("Survey_form").Range("A" & i).Value = "surveyor" Then
UPDATE:
After changing my code, which now looks like this:
Sub FrontsheetAdd3()
Dim x As Workbook, y As Workbook, sPath As String
Dim i As Long
sPath = ThisWorkbook.Path & "\Survey_form.csv"
Set x = Workbooks.Open(sPath)
Set y = ActiveWorkbook.Sheets("Frontsheet") 'set to current worksheet name
'Name of the sheet is the same as Name of the workbook 1
For i = 1 To 40
If x.Sheets("Survey_form").Range("A" & i).Value = "surveyor"
Then
x.Sheets("Survey_form").Rage("B" & i).Value = ("A" & i)
y.Sheets("Frontsheet").Range("D34").PasteSpecial
End If
Next i
End Sub
At the line:
Set y = ActiveWorkbook.Sheets("Frontsheet") 'set to current worksheet name
my active workbook (Workbook2), where the macro is meant to be is closing down and error Subscript out of range emerges.
What is missig then?
Please, try the next adapted code. It will copy from the csv file in the active one and exit loop:
Sub FrontsheetAdd3()
Dim x As Workbook, y As Worksheet, ws As Worksheet, sPath As String, i As Long
sPath = ThisWorkbook.path & "\Survey_form.csv"
Set y = ActiveWorkbook.Sheets("Frontsheet") 'set to current worksheet name
Set x = Workbooks.Open(sPath): Set ws = x.Sheets(1)
For i = 1 To 40
If ws.Range("A" & i).value = "surveyor" Then
y.Range("D34").value = ws.Rage("B" & i).value: Exit For
End If
Next i
End Sub
A VBA Lookup
Use Option Explicit which forces you to declare all variables.
Use variables (more of them) to make the code more readable.
Use meaningful variable names: sPath is a great name while x and y used for workbooks are terrible.
Instead of the loop, use Application.Match.
You can basically copy in three ways: Copy, Copy with PasteSpecial or Copy by Assignment (dCell.Value = sCell.Value) the latter being the most efficient when copying only values.
Option Explicit
Sub FrontsheetAdd3()
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets("Frontsheet")
Dim dCell As Range: Set dCell = dws.Range("D34")
Dim sPath As String: sPath = dwb.Path & "\Survey_form.csv"
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
Dim sws As Worksheet: Set sws = wb.Worksheets("Survey_form")
' Determine the position of the first occurence of "surveyor" in column 'A'.
Dim sIndex As Variant
sIndex = Application.Match("surveyor", sws.Columns("A"), 0)
If IsNumeric(sIndex) Then ' "suveyor" was found
Dim sCell As Range: Set sCell = sws.Rows(sIndex).Columns("B")
dCell.Value = sCell.Value
Else ' "surveyor" was not found
dCell.Value = ""
End If
swb.Close SaveChanges:=False
'dwb.Save
End Sub
I am working on a Macro to extract data from different rows (there are some blank rows) but I want it to search and extract instead of from a range to extract from columns A-D this can be from (A1:D100) then to stop the loop if A(x) where the content of X is "Results". Then to loop to the next workbook.
Sub tgr()
Dim wbDest As Workbook
Dim wsDest As Worksheet
Dim rCopy As Range
Dim sFolder As String
Dim sFile As String
Dim lRow As Long
Set wbDest = ThisWorkbook 'The workbook where information will be copied into
Set wsDest = wbDest.Worksheets("Sheet1") 'The worksheet where information will be copied into
sFolder = "C:\Path\" 'The folder path containing the xlsx files to copy from
'would like sFolder to be the root folder and also
' search for any "*.xlsx" contained inside C:\temp
lRow = 1 'The starting row where information will be copied into
'Adjust the folder path to ensure it ends with \
If Right(sFolder, 1) <> "\" Then sFolder = sFolder & "\"
'Get the first .xlsx file in the folder path
sFile = Dir(sFolder & "*.xlsx")
'Begin loop through each file in the folder
Do While Len(sFile) > 0
'Open the current workbook in the folder
With Workbooks.Open(sFolder & sFile)
'Copy over the formulas from A1:C3 from only the first
' worksheet into the destination worksheet
Set rCopy = .Sheets(1).Range("C9:D26")
wsDest.Cells(lRow, "A").Resize(rCopy.Rows.Count, rCopy.Columns.Count).Formula = rCopy.Formula
'Advance the destination row by the number of rows being copied over
lRow = lRow + rCopy.Rows.Count
.Close False 'Close the workbook that was opened from the folder without saving changes
End With
sFile = Dir 'Advance to the next file
Loop
End Sub
Code 1 is used to find the FIRST occurrence of the string we search for:
Option Explicit
Sub test()
Dim rngSearch As Range, Position As Range
Dim strSearch As String
With ThisWorkbook.Worksheets("Sheet1")
Set rngSearch = .Range("A1:D100") '<- Set the range i want to search in
strSearch = "Test" '<- Set the string i want to search for
Set Position = rngSearch.Find(strSearch) '<- Search for string in range
If Not Position Is Nothing And .Range("A" & Position.Row).Value = "Results" Then '<- Check if string appears in the range and the value in column A and row where the string is "Results"
'Code here
End If
End With
End Sub
Code 2 is used to search the whole range and check ALL occurrence of string we search for:
Option Explicit
Sub test()
Dim rngSearch As Range, cell As Range
Dim strSearch As String
With ThisWorkbook.Worksheets("Sheet1")
Set rngSearch = .Range("A1:D100") '<- Set the range i want to search in
strSearch = "Test" '<- Set the string i want to search for
For Each cell In rngSearch
If cell.Value = strSearch And .Range("A" & cell.Row).Value = "Results" Then
'Code here
End If
Next cell
End With
End Sub
I've been trying to scavange together a macro which will merge several .CSV files.
However, the data I need in said file (GPS data) is located in different rows of column A. I therefor need it to search for part of a string, in this case there are a few strings related to GPS, but I only need GPS latitud and longitude (which will always be found one after another).
Any help is appreciated! The code might look a bit.. like shit, ive been trying to mess with it to make it work together!
Sub MergeAllWorkbooks()
Dim SummarySheet As Worksheet
Dim FolderPath As String
Dim directory As Object
Dim NRow As Long
Dim FileName As String
Dim WorkBk As Workbook
Dim SourceRange As Range
Dim DestRange As Range
Dim S_Lat, S_Long, D_Lat, D_Long As Range
Dim i As Integer
Dim icount As Integer
Dim icount2 As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
If .Show = -1 Then '-1 = yes or true
FolderPath = .SelectedItems(1) & "\"
Else
MsgBox "FilePath not selected!", , "Path selecter"
Exit Sub
End If
End With
' Create a new workbook and set a variable to the first sheet.
Set SummarySheet = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
' NRow keeps track of where to insert new rows in the destination workbook.
NRow = 2
' Call Dir the first time, pointing it to all .csv files in the folder path.
FileName = dir(FolderPath & "*.csv")
SummarySheet.Range("A1") = "Filnamn"
SummarySheet.Range("B1") = "Latitud"
SummarySheet.Range("C1") = "Longitud"
' Loop until Dir returns an empty string.
Do While FileName <> ""
' Open a workbook in the folder
Set WorkBk = Workbooks.Open(FolderPath & "\" & FileName)
' Set the cell in column A to be the file name.
SummarySheet.Range("A" & NRow).Value = FileName
' Set the source range to be A9 through C9.
' Modify this range for your workbooks.
' It can span multiple rows.
For i = 1 To 200
If InStr(1, LCase(Range("A" & i)), "GPS Latitude") <> 0 Then 'If GPS appears in the string then
icount = i
icount2 = icount + 1
Set S_Lat = WorkBk.Worksheets(1).Range("A" & icount) ' Set the S_Lat variable
Set S_Long = WorkBk.Worksheets(1).Range("A" & icount2) ' Set the S_Long variable
Exit For
End If
Next i
' Set the destination range to start at column B and
' be the same size as the source range.
' SummarySheet.Range("B" & NRow).Value = S_Lat.Value ***** Didnt work? ******
' SummarySheet.Range("C" & NRow).Value = S_Long.Value ***** Didnt work? ******
Set D_Lat = SummarySheet.Range("B" & NRow)
Set D_Long = SummarySheet.Range("C" & NRow)
' Copy over the values from the source to the destination.
D_Lat.Value = S_Lat.Value
D_Long.Value = S_Long.Value
' Increase NRow so that we know where to copy data next.
NRow = NRow + D_Lat.Rows.Count
' Close the source workbook without saving changes.
WorkBk.Close savechanges:=False
' Use Dir to get the next file name.
FileName = dir()
Loop
' Call AutoFit on the destination sheet so that all
' data is readable.
' SummarySheet.Columns.AutoFit
End Sub
This simple code is not giving you a complete working macro, it will Look for "Latitude" in column A and when found it will transfer the cel.value, and the cel.value below it, to two rows side-by-side in column B and column C on the same worksheet. You will need to wrap it inside your Workbooks.Open loop, modify the Range in the source worksheet to include a last row, include a last row for your new workbook's worksheet and add it to the code inside the If statement. Try to work this into your code and when you encounter problems, you can return to SO and ask a specific question concerning your macro. The macro was tested with actual longitudes and latitudes, in column A, an placed in columns B and C side-by-side.
Dim lRow As Long
lRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
For Each cel In Range("A1:A38")
If InStr(1, cel.Value, "Latitude") Then
x = x + 1
Cells(x, 2).Value = cel.Value
Cells(x, 3).Value = cel.Offset(1).Value
End If
Next cel
First time poster here.
I have a list of files (file1, file2, file3) and I want to copy a range from those files into a master file. The master file contains a column with this data file1, file2, file3. How can I loop through that column and copy and paste each file's range into the corresponding row in the master? I need the data from file1 to go into a range in the same row as file1.
This is what I have so far:
Dim col As Range
Dim cell As Range
Dim currentRow As Long
Dim varCellValue As String
Dim pasteRangeC As String
Dim pasteRangeE As String
Set col = Range("B3:B5")
currentRow = 3
For Each cell In col
varCellValue = cell.Value
currentRow = 3
pasteRangeC = "C" & currentRow
pasteRangeE = "E" & currentRow
'## Open workbooks:
Set x = Workbooks.Open("C:\Folder\" & varCellValue &_ ".xlsx")
Set y = ThisWorkbook
'Copy from x:
x.Sheets("Summary").Range("D13:F13").Copy
'Paste to y worksheet:
y.Sheets("Sheet1").Range(pasteRangeC & ":" & pasteRangeE).PasteSpecial xlPasteValues
'Close x:
x.Close
currentRow = currentRow + 1
Next
End Sub
The code works for the first loop then I get a run-time error 1004 that the file cannot be found. So I'm thinking the varCellValue does not get the next cell's value.
Can anyone point me in the right direction?
Based on what I read try the following
Option Explicit 'Use every time will keep you from making simple mistakes...
Sub test()
Dim wb As Workbook
Dim ws As Worksheet
Dim wbSource As Workbook
Dim i As Integer
On Error GoTo ErrCatch 'add to catch errors
Set wb = Application.ThisWorkbook
Set ws = wb.Worksheets("Sheet1")
For i = 1 To 5
'## Open workbooks:
Set wbSource = Workbooks.Open("C:\Folder\" & ws.Cells(i, 2).Value & ".xlsx") 'Cells(Row,Column) 2 = "B"
'Copy from wbSource and paste in worksheet
wbSource.Sheets("Summary").Range("D13:F13").Copy Destination:=ws.Cells(i, 3) 'This syntax keeps you from having to do "Application.CutCopyMode = False" to remove the marching ants.
'Close source:
wbSource.Close False
Next i
ErrCatch:
If Err.Number > 1 Then 'test if an error was thrown
MsgBox "Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description, vbCritical
End If
End Sub