I am new at creating macros. Only created 5 of them for specific problems.
Could someone help me amend the below macro? I found it on the internet, I amended it to my preferences. But still there is room from improvement. Anyways it works perfectly except for the below.
There would be a lot of files in folder. Each file contains a tab named "PIVOT", where the format are the same, but the amount of data are different.
The range is in the PIVOT tab are from A to AM columns. They start at row 15. And I would only need those lines where the "closed" indication is not written (Status column is in AJ column). I want all of these rows to be copied into a master file under each other. The amount of rows varies greatly - like 0 to 200 depending on the open items.
Secondly, can someone tell me a book, that could be purchased so that I could evolve my knowledge?
Thank For your help!
Tibor
Sub Import_to_Master()
Dim sFolder As String
Dim sFile As String
Dim wbD As Workbook, wbS As Workbook
Application.ScreenUpdating = False
Set wbS = ThisWorkbook
sFolder = wbS.Path & "\"
sFile = Dir(sFolder)
Do While sFile <> ""
If sFile <> wbS.Name Then
Set wbD = Workbooks.Open(sFolder & sFile) 'open the file; add condition to
' >>>>>> Adapt this part
wbD.Sheets("PIVOT").Range("A15:AM26").Copy
wbS.Activate
Sheets("Template").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
' >>>>>>
wbD.Close savechanges:=True 'close without saving
End If
sFile = Dir 'next file
Loop
Application.ScreenUpdating = True
End Sub
you may be after this:
' >>>>>> Adapted part
With wbD.Sheets("PIVOT")
With .Range("AM14", .Cells(.Rows.count, 1).End(xlUp)) '<--| reference its column "A:AM" range from row 14 down to column "A" last not empty row
.AutoFilter Field:=36, Criteria1:="<>closed" '<--| filter referenced range on its 36th column (i.e. column "AJ") with values different from "closed"
If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then
.Resize(.Rows.count - 1).Offset(1).SpecialCells(xlCellTypeVisible).Copy
Sheets("Template").Range("A" & Rows.count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
End If
End With
.AutoFilterMode = False
End With
' >>>>>>
If you need to check each row for a certain cell value use something like the following. This will loop through line by line checking for lines that don't say "Closed".
Dim sFolder As String, sFile As String, wbD As Workbook, wbS As Workbook
Dim lastRowS As Integer, lastRowD As Integer
Application.ScreenUpdating = False
Set wbS = ThisWorkbook
sFolder = wbS.Path & "\"
sFile = Dir(sFolder
lastRowS = Sheets("Template").Range("A" & Rows.Count).End(xlUp).Row + 1
Do While sFile <> ""
If sFile <> wbS.Name Then
Set wbD = Workbooks.Open(sFolder & sFile) 'open the file; add condition to
lastRowD = wbD.Sheets("PIVOT").Range("A" & Rows.Count).End(xlUp).Row
For i = 15 To lastRowD
If Cells(i, 3) <> "Closed" Then 'change 3 to whatever column number has Closed in
wbD.Sheets("PIVOT").Rows(i).EntireRow.Copy
wbS.Sheets("Template").Cells(lastRowS, 1).PasteSpecial xlPasteValues
lastRowS = lastRowS + 1
End If
Next i
Application.CutCopyMode = False
' >>>>>>
wbD.Close savechanges:=False 'close without saving
End If
sFile = Dir 'next file
Loop
Application.ScreenUpdating = True
End Sub
Related
I wanted to create macro to filter the data and save new file for each filter criteria
Have got below code but I am getting compile error : wrong number of arguments or invalid property assigned on below line
Set filteredData = dataRange.Offset(1, 0).Resize(dataRange.Rows.Count - 1, dataRange.Columns.Count).SpecialCells(xlCellTypeVisible)
At .resize
Below is the entire code.
Sub FilterAndSave()
Dim filterRange As Range, dataRange As Range, filteredData As Range
Dim lastRow As Long, i As Long
Dim folderPath As String, fileName As String
'set filter range and data range
Set filterRange = Sheet1.Range("A1:A8")
Set dataRange = Sheet2.Range("A1").CurrentRegion
'turn off alerts and screen updating
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'loop through each filter criteria
For i = 1 To filterRange.Rows.Count
'set filter
dataRange.AutoFilter Field:=1, Criteria1:=filterRange.Cells(i, 1).Value
'check if any cells are visible
On Error Resume Next
Set filteredData = dataRange.Offset(1, 0).Resize(dataRange.Rows.Count - 1, dataRange.Columns.Count).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not filteredData Is Nothing Then
'copy and save filtered data
folderPath = filterRange.Cells(i, 1).Value & "\"
If Len(Dir(folderPath, vbDirectory)) = 0 Then MkDir folderPath
fileName = filterRange.Cells(i, 1).Value & ".xlsx"
filteredData.Copy
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs folderPath & fileName, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
ActiveWorkbook.Close False
filteredData.EntireRow.Delete
End If
Next i
'turn on alerts and screen updating
Application.DisplayAlerts = True
Application.ScreenUpdating = True
'check if any data is left
If WorksheetFunction.CountA(dataRange) > 1 Then
MsgBox "Some data is not filtered", vbExclamation
End If
End Sub
I want macro to check all the filter criteria and save file for each filtered data and at the end it should give msg box if any data left which is not in filter criteria
Your loop needs to deal with the possibility that no rows are returned by the filter, before attempting to load that range to a Range object. One method would be to alter your loop like so:
For i = 1 To filterRange.Rows.Count
'set filter
dataRange.AutoFilter Field:=1, Criteria1:=filterRange.Cells(i, 1).Value
'if more than 1 row (just the header) visible..
If dataRange.SpecialCells(xlCellTypeVisible).Address <> dataRange.Rows(1).Address Then
Set filteredData = dataRange.Offset(1, 0).Resize(dataRange.Rows.Count - 1, dataRange.Columns.Count).SpecialCells(xlCellTypeVisible)
'copy and save filtered data
folderPath = filterRange.Cells(i, 1).Value & "\"
If Len(Dir(folderPath, vbDirectory)) = 0 Then MkDir folderPath
Filename = filterRange.Cells(i, 1).Value & ".xlsx"
filteredData.Copy
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs folderPath & Filename, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
ActiveWorkbook.Close False
filteredData.EntireRow.Delete
End If
Next i
I have a code that loops through all the workbooks in a user selected folder and fetch the column names from all the sheets. Note that there may be multiple column names in a single sheet tab. So, the code searches in first column that contains "Product" in it and copies the entire row until last non empty column and pastes them in ThisWorkbook.Sheets("Column Names").
This code opens the workbook, searches for the text "Product" in each sheet tab, copies the column names and closes the workbook without saving.
I am using the below code to fetch the column names. It works completely fine for only 1 workbook and when the code opens the second workbook, it throws error in the line highlighted.
Anybody please help me to identify where I have done wrong.
Option Explicit
Dim i, ShtCnt As Integer
Dim ws, CurSht As Excel.Worksheet
Dim cell As Range
Dim EmpCell As Integer
Dim NonEmpCell As Integer
Dim lRow As Long
Dim ThiswblRow, ThiswblRow2 As Long
Dim lCol As Long
Dim FldrPicker As FileDialog
Dim wb As Workbook
Dim myExtension, filepath, filepathSrc, filepathDest, fileSaveName, filename, Template, TempLocPath, ShtNameRaw, ShtNameTemp, SlrName As String
'Step 1
Public Sub LoopAllExcelFilesInAFolder()
'Optimize Macro Speed
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
'Retrieve Target Folder Path From User
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
filepath = .SelectedItems(1) & "\"
End With
'In Case of Cancel
NextCode:
filepath = filepath
If filepath = "" Then GoTo ResetSettings
'Target File Extension (must include wildcard "*")
myExtension = "*.xls*"
'Target Path with Ending Extention
TempLocPath = Dir(filepath & myExtension)
'Loop through each Excel file in folder
Do While TempLocPath <> ""
'Set variable equal to opened workbook
Set wb = Workbooks.Open(filename:=filepath & TempLocPath)
filename = ActiveWorkbook.Name
Workbooks(filename).Activate
'Call Find_Product_in_each_sheet_loop
For ShtCnt = 1 To ActiveWorkbook.Worksheets.Count
'On Error Resume Next
Set ws = ActiveWorkbook.Worksheets(ShtCnt)
lRow = ws.Range("A100000").End(xlUp).Row --> Getting error in this line
'Call Find_Product(ws)
For i = 1 To lRow
lRow = ws.Range("A100000").End(xlUp).Row
If InStr(ws.Cells(i, 1), "Product") <> 0 Or InStr(ws.Cells(i, 1), "Model") <> 0 Then
ThiswblRow = ThisWorkbook.Sheets("Column Names").Range("B100000").End(xlUp).Row + 1
'Workbook Name
ThisWorkbook.Sheets("Column names").Range("B" & ThiswblRow) = ActiveWorkbook.Name
ws.Activate
'Sheet Name
ThisWorkbook.Sheets("Column names").Range("C" & ThiswblRow) = ActiveSheet.Name
lCol = ws.Cells(i, Columns.Count).End(xlToLeft).Column
ws.Range(Cells(i, 1), Cells(i, lCol)).Select
'Column Names
ws.Range(Cells(i, 1), Cells(i, lCol)).Copy ThisWorkbook.Sheets("Column Names").Range("D" & ThiswblRow)
End If
Next i
ThiswblRow = Empty
lRow = Empty
'Next j
Next ShtCnt
ThiswblRow = ThisWorkbook.Sheets("Column Names").Range("A100000").End(xlUp).Row + 1
ThiswblRow2 = ThisWorkbook.Sheets("Column Names").Range("B100000").End(xlUp).Row
'Partner Name
Workbooks(filename).Sheets("Request Form").Activate
Workbooks(filename).Sheets("Request Form").Columns(1).Select
With Selection
.Find(What:="Partner Name", After:=ActiveCell, LookIn:= _
xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
xlNext, MatchCase:=False, SearchFormat:=False).Activate
ActiveCell.Offset(0, 1).Copy ThisWorkbook.Sheets("Column Names").Range("A" & ThiswblRow & ":A" & ThiswblRow2)
End With
lRow = Empty
ThiswblRow = Empty
ThiswblRow2 = Empty
'Close Workbook without saving
wb.Close SaveChanges:=False
'Get next file name
TempLocPath = Dir
Loop
ThisWorkbook.Sheets("Column Names").UsedRange.WrapText = False
ResetSettings:
'Reset Macro Optimization Settings
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
MsgBox ("Done")
End Sub
Most likely you have an Excel file in the old format (*.xls). In the old format, sheets had only 64k rows, so using something like A100000 fails because there is simply no such cell.
Don't use such magic numbers. The total number of rows in a sheet is ws.rows.count, and
that works no matter how many rows a sheet has. Change the line to
lRow = ws.Cells(ws.rows.count, 1).End(xlUp).Row
or, if you prefer
lRow = ws.Range('A' & ws.rows.count).End(xlUp).Row
P.S.: You should indent your code, the way you presented it is nearly unreadable. I was about to give because it is nearly impossible to tell where loops start and end.
I'm very new to VBA and I'm working on a project where I've got multiple Excel files in a folder, each structured the same way, and I want to loop through each of them, search for specific terms in each single file, copy it, and paste it to the master-file in a specific way.
I already got everything except pasting it the right way:
Every term it finds in a source-file should be posted to the next empty column in the master file and for each new source-file the loop goes through, it should post the stuff it finds to a new row in the master file.
Below is what I've already got.
Private Const sPath As String = "F:\ExamplePath"
Sub LoopThroughFiles()
Dim sFile As String 'File Name
Dim sExt As String 'File extension
sExt = "xlsx"
'loop through each file name and open it if the extension is correct
sFile = Dir(sPath)
Do Until sFile = ""
If Right(sFile, 4) = sExt Then GetInfo sFile
sFile = Dir
Loop
End Sub
Private Sub GetInfo(sFile As String)
Dim wbFrom As Workbook 'workbook to copy the data from
Dim iRow As Integer 'row number of next empty row
Dim cl As Range
Dim strAddress As String
On Error GoTo errHandle
Application.EnableEvents = False
Application.ScreenUpdating = False
Set wbFrom = Workbooks.Open(sPath & sFile)
'finds Search-Term
With wbFrom.Sheets(1).Cells
Set cl = .Find("necrosis_left", After:=.Range("C2"), LookIn:=xlValues)
If Not cl Is Nothing Then
strAddress = cl.Address
cl.Select
Selection.Copy
iRow = Me.Range("A" & Rows.Count).End(xlUp).Row + 1 'Get an empty row in this workbook
Me.Range("A" & iRow).PasteSpecial xlPasteAll 'past copied cells
End If
End With
'finds other Search-Term
With wbFrom.Sheets(1).Cells
Set cl = .Find("necrosis_right", After:=.Range("C2"), LookIn:=xlValues)
If Not cl Is Nothing Then
strAddress = cl.Address
cl.Select
Selection.Copy
iRow = Me.Range("A" & Rows.Count).End(xlUp).Row + 1 'Get an empty row in this workbook
Me.Range("A" & iRow).PasteSpecial xlPasteAll 'past copied cells
End If
End With
'many more search terms
wbFrom.Close (False)
Application.EnableEvents = True
Application.ScreenUpdating = True
Set wbFrom = Nothing
Exit Sub
errHandle:
MsgBox Err.Description
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
So I do know, that my problem is located here:
iRow = Me.Range("A" & Rows.Count).End(xlUp).Row + 1 'Get an empty row in this workbook
Me.Range("A" & iRow).PasteSpecial xlPasteAll 'past copied cells
But I can't quite figure out how it posts to an empty column instead of an empty row, not to speak of how to make it go down a row in the master file for each new source file.
Found the answer to my own question!
The first step was to replace the "paste-line" above with the following:
Me.Cells(1, Columns.Count).End(xlToLeft).Offset(0, 1).PasteSpecial xlPasteAll
This pastes every copied cell to the next empty column in line 1.
To start a new line for every source-file the loop goes through, a public variable had to be declared, which counted up each iteration. The final code looks like this:
Private Const sPath As String = 'enter your path
Public Zeile As Integer 'public variable
Sub LoopThroughFiles()
Dim sFile As String 'File Name
Dim sExt As String 'File extension you wish to open
Zeile = 1 'important for not start pasting in row 0 (which is impossible)
sExt = "xlsx" 'Change this if extension is different
'loop through each file name and open it if the extension is correct
sFile = Dir(sPath)
Do Until sFile = ""
If Right(sFile, 4) = sExt Then GetInfo sFile
sFile = Dir
Zeile = Zeile + 1 'goes up each iteration
Loop
End Sub
Private Sub GetInfo(sFile As String)
Dim wbFrom As Workbook 'workbook to copy the data from
Dim iRow As Integer 'row number of next empty row
Dim cl As Range
Dim strAddress As String
On Error GoTo errHandle
Application.EnableEvents = False
Application.ScreenUpdating = False
Set wbFrom = Workbooks.Open(sPath & sFile)
'copy the following block for each term you want to search for
With wbFrom.Sheets(1).Cells
Set cl = .Find("searchterm", After:=.Range("C2"), LookIn:=xlValues)
If Not cl Is Nothing Then
strAddress = cl.Address
cl.Select
Selection.Copy
Me.Cells(Zeile, Columns.Count).End(xlToLeft).Offset(0, 1).PasteSpecial xlPasteAll 'the rows are controlled via the public variable
End If
End With
wbFrom.Close (False)
Application.EnableEvents = True
Application.ScreenUpdating = True
Set wbFrom = Nothing
Exit Sub
errHandle:
MsgBox Err.Description
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
The result loops through all files of a folder, searches for a specific term and pastes each result in the next empty column of the master file, but starts a new row for each source file.
Thanks though!
I am trying to copy Range(A14:N26) from every closed workbook in a folder on my desktop and paste them into the current worksheet (which is my master worksheet). The code does grab the right range of data but struggles with the pasting part.
It is supposed to SpecialPaste the code as there are formulas in the cells and I want to only copy what is visible in the cells. (Note: The outcome of some of of the formulas are words, the outcome of others are numbers)
Option Explicit
Sub CopySheetFromFileOnDesktop()
Dim wkbDest As Workbook
Dim wksDest As Worksheet
Dim wkbSource As Workbook
Dim wksSource As Worksheet
Dim MyPath As String
Dim MyFile As String
Dim SheetIndex As Integer
Application.ScreenUpdating = False
Set wkbDest = ThisWorkbook
Set wksDest = wkbDest.Worksheets("Master Sheet")
SheetIndex = 1
MyPath = "C:\Users\.."
If Right(MyPath, 1) <> "\" Then MyPath = MyPath & "\"
MyFile = Dir(MyPath & "*.xlsm")
Do While Len(MyFile) > 0
Set wkbSource = Workbooks.Open(MyPath & MyFile)
Set wksSource = wkbSource.Worksheets("Sheet containing the info")
If WorksheetFunction.CountA(wkbSource.Sheets("Sheet containing the
info").Range("A14:L26")) <> 0 Then
'lRow = .Range("L" & Rows.Count).End(xlUp).Row 'UNSURE HOW TO LAST ROW
wkbSource.Sheets("Sheet containing the info").Range("A14:L26").Copy
wkbDest.Range("A:L" & Rows.Count).End(xlUp)(2).PasteSpecial _
Paste:=xlPasteValues 'PASTESPECIAL SEEMS TO BE THE PROBLEM
wkbSource.Close savechanges:=False
Application.CutCopyMode = False
Else
End If
Loop
Application.ScreenUpdating = True
MsgBox "Completed...", vbInformation
End Sub
when running the macro it shows this bug: Runtime Error 438: Object does not support Properties or Method. And the debugger highlights the line where I define where to paste the copied range
The code row with your destination range needs an optimization:
You erroneously used wkbDest instead of wksDest
A partly row can not be addressed by Range("A:L" & 1000)
If you use Rows.Count without a leading dot, then the ActiveSheet is assumed
First attempt
wksDest.Cells(wksDest.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize(1, 12).PasteSpecial _
Paste:=xlPasteValues
The destination is built as follows:
Find the last used cell in column 1 (e. g. A100)
Offset it to the next row (e. g. A101)
Resize it to a new dimension of 1 row and 12 columns (e. g. A101:L101)
Second attempt:
If you paste, it is only necessary to address the first cell of the destination. So following should also work:
wksDest.Cells(wksDest.Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial _
Paste:=xlPasteValues
Recommendation:
If you define source and destination range of the same size, you can just assign their values (simular to PastSpecial of values, but faster):
wksDest.Cells(wksDest.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize(1, 12).Value = _
wksSource.Range("A14:L26").Value
I am very new to the world of code and VBA - but I am having a lot of fun learning and exploring just how powerful these tools are.
I am working on pulling data from one worksheet and placing it in my "master roadmap" spreadsheet. Just a little background: In the master sheet, I have been inserting data in columns A-S; however, column 'A' is reserved on the worksheet I am pulling data from so this is why the range below is set as Range (B:T). I am scanning columns by B:T; pulling that data and inserting it in columns A:S of my master sheet. However, my boss wants to make a change reserve columns "U' through "AD" on her spreadsheet.
So I would like to have VBA scan through two ranges "B:T" and then "AE:BB" (skipping U:AD) and then plug that information in my "master sheet" into columns "A:AQ."
In short, I am hoping all I have to do is insert a 'second range' in the code below to complete this task. Any help would be greatly appreciated!
Sub LoopThroughDirectory()
Dim MyFile As String
Dim erow As Double
Dim lastrow As Double
Dim MasterWorkbook As Workbook
Dim TempWorkbook As Workbook
Dim DirPath As String
'Clear current data
Sheet1.Visible = xlSheetVisible
Sheet2.Visible = xlSheetHidden
Sheet3.Visible = xlSheetHidden
Sheet1.Activate
lastrow = ActiveWorkbook.ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
If lastrow > 1 Then
Range("A2:AQ" & lastrow).Select
Selection.Clear
End If
DirPath = "C:\Users\rspktcod\Documents\RoadMap Test\Roadmaps\"
MyFile = Dir(DirPath)
Set MasterWorkbook = ActiveWorkbook
Do While Len(MyFile) > 0
Set TempWorkbook = Workbooks.Open(DirPath & MyFile)
lastrow = ActiveWorkbook.ActiveSheet.Range("B" & Rows.Count).End(xlUp).Row
Range("B2:T" & lastrow).Copy
MasterWorkbook.Activate
erow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Paste Destination:=Worksheets("Roadmap").Range(Cells(erow, 1), Cells(erow, 43))
TempWorkbook.Activate
Application.CutCopyMode = False
ActiveWorkbook.Close
MyFile = Dir
Loop
End Sub
The short answer is, yes, you can just add another range.
Here is the long answer (with a few improvments...):
Sub LoopThroughDirectory()
Dim DirPath As String, MyFile As String
Dim LastRow As Long, eRow As Long ' Rows should be Long
'Dim MasterWorkbook As Workbook
Dim TempWorkbook As Workbook
Dim DestSheet As Worksheet
'Clear current data
Sheet1.Visible = xlSheetVisible
Sheet2.Visible = xlSheetHidden
Sheet3.Visible = xlSheetHidden
' Added DestSheet to be more clear, since Sheet1 is specific to this file.
' It also make the code more portable, if you want to change it to a different sheet, in a different file.
Set DestSheet = Sheet1
' MasterWorkbook is a good idea, but not required here.
'Set MasterWorkbook = ThisWorkbook 'ActiveWorkbook
LastRow = DestSheet.Range("A" & Rows.Count).End(xlUp).Row
If LastRow > 1 Then Range("A2:AQ" & LastRow).Clear
DirPath = "C:\Users\rspktcod\Documents\RoadMap Test\Roadmaps\"
' Added "*.xls*" to limit it to just Excel Workbooks
' You don't want to process the current and previous folders, which come across as "." & ".."
MyFile = Dir(DirPath & "*.xls*")
Do While Len(MyFile) > 0
Set TempWorkbook = Workbooks.Open(DirPath & MyFile)
' Used [TempWorkbook.ActiveSheet].Rows.Count, instead of just Rows.Count to be more percise
With TempWorkbook.ActiveSheet ' <-- Not a fan of Activesheet here
LastRow = .Range("B" & .Rows.Count).End(xlUp).Row
If LastRow > 1 Then
' Excel 2003-/2007+ have different number of rows, so be specific about what sheet to get the Rows from
eRow = DestSheet.Cells(DestSheet.Rows.Count, 1).End(xlUp).Row + 1
.Range("B2:T" & LastRow).Copy Destination:=DestSheet.Cells(eRow, 1)
.Range("AE2:BB" & LastRow).Copy Destination:=DestSheet.Range("T" & eRow)
End If
TempWorkbook.Close False ' Added SaveSanges = False for good measure
MyFile = Dir
End With
Loop
End Sub