Today with VBA I was trying to come with something that would modify several .xlsx files in a folder and then would copy and paste the data to another worksheet. In one of the steps, I am trying to select and delete specific columns from the other Excel file based on headers' names in VBA. The columns I would like to remove are all between the headers named "Unsubscribed" and "Webinar Question 1". The issue is that when it come to this part, it gives me an error 91:
With Worksheets("Sheet0").Range("A1:BB1")
Range(Worksheets("Sheet0").Range("A1:BB1").Find(What:="Unsubscribed", LookIn:=xlValues, MatchCase:=False).Offset(0, 1), _
Cells(Worksheets("Sheet0").Cells(Worksheets("Sheet0").Rows.Count, "A").End(xlUp).Row, _
Worksheets("Sheet0").Range("A1:BB1").Find(What:="Webinar Question 1", LookIn:=xlValues, MatchCase:=False).Offset(0, -1).Column) _
).Select
End With
The whole VBA is:
Private Sub CommandButton1_Click()
Dim my_files As String
Dim folder_path As String
Dim wb As Workbook, lRow As Long
Dim ws As Worksheet, LR As Long
Dim wsCopy As Worksheet
Dim wsDest As Worksheet
Dim lCopyLastRow As Long
Dim lDestLastRow As Long
folder_path = "C:\Users\XXXX\Desktop\"
my_files = Dir(folder_path & "\*.xlsx")
Do While my_files <> vbNullString
Set wb = Workbooks.Open(folder_path & "\" & my_files)
Set ws = wb.Worksheets("Sheet0")
'INSERT COLUMN AND PASTE FILE NAME IN ALL ROWS UNTIL LAST ROW
LR = ws.Range("B9").End(xlDown).Row
ws.Columns(1).Select
ActiveCell.EntireColumn.Insert
ws.Range("A8").Value = "Title"
ws.Range("A9:A" & LR).Value = ActiveWorkbook.Name
'INSERT COLUMN AND PASTE CELL A5 VALUE IN ALL ROWS UNTIL LAST ROW
ws.Columns(2).Select
ActiveCell.EntireColumn.Insert
ws.Range("B8").Value = "Duration"
ws.Range("B9:B" & LR).Value = ws.Range("E5").Value
'DELETE A1:A7 ROWS
ws.Range("A1:A7").EntireRow.Delete
'DELETE ORGANIZATION COLUMN
Dim rng As Range
With Worksheets("Sheet0").Range("A1:BB1")
Set rng = Worksheets("Sheet0").Range("A1:BB1").Find(What:="Organization", _
lookat:=xlWhole, MatchCase:=False)
Do While Not rng Is Nothing
rng.EntireColumn.Delete
Set rng = .FindNext
Loop
End With
'SELECT AND DELETE ALL COLUMNS BETWEEN UNSUBSCRIBED AND WEBINAR QUESTION 1
With Worksheets("Sheet0").Range("A1:BB1")
Range(Worksheets("Sheet0").Range("A1:BB1").Find(What:="Unsubscribed", LookIn:=xlValues, MatchCase:=False).Offset(0, 1), _
Cells(Worksheets("Sheet0").Cells(Worksheets("Sheet0").Rows.Count, "A").End(xlUp).Row, _
Worksheets("Sheet0").Range("A1:BB1").Find(What:="Webinar Question 1", LookIn:=xlValues, MatchCase:=False).Offset(0, -1).Column) _
).Select.Delete
End With
Set wsCopy = Worksheets("Sheet0")
Set wsDest = Workbooks("Book1.xlsm").Worksheets("Sheet2")
lCopyLastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(1).Row
lDestLastRow = wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Offset(1).Row
wsCopy.Range("A2:BB1" & lCopyLastRow).Copy _
wsDest.Range("A" & lDestLastRow)
wb.Close True
my_files = Dir()
Loop
MsgBox ("All Files Are Updated")
End Sub
For clarification, the worksheet where I have the VBA has Sheet1 and Sheet2, and the file that i am modifying has Sheet0.
What am I missing? Thank you very much and have a nice day.
Related
I am trying to copy data from a .xlsm to a .xlsx file in SharePoint (SP). My code does several other things for moving data but the issue I am having is getting the source row from 1 doc to another doc in SP.
I am hoping someone can assist.
Sub Complete()
Dim tb1 As ListObject, tb2 As ListObject
Dim Lrow As Long, dRow As Long
Dim ws As Worksheet, ws1 As Worksheet
Dim searchRange As Range, foundCell As Range
Dim mysearch As String
Dim wb As Workbook, Scwb As Workbook
Application.DisplayAlerts = False
Set wb = ThisWorkbook
Set ws = wb.Sheets("OI")
mysearch = ws.Range("D4").Value
Set tb1 = ws.ListObjects("OITs")
Set tb2 = wb.Sheets("TDets").ListObjects("OIFinal")
Lrow = tb2.ListRows.Count
With ws
.Range("A:A").EntireColumn.Hidden = False
End With
tb1.Range.AutoFilter Field:=11, Criteria1:="<>" & vbNullString
NumRows = tb1.DataBodyRange.Cells.SpecialCells(xlCellTypeVisible).Rows.Count
tb1.DataBodyRange.Cells.SpecialCells(xlCellTypeVisible).Copy
tb2.DataBodyRange(Lrow + 1, 1).PasteSpecial xlPasteValues
Application.CutCopyMode = False
tb1.DataBodyRange.Columns(4).Resize(, 7).ClearContents
tb1.Range.AutoFilter Field:=11, Criteria1:="=" & vbNullString
With ws
.Range("A:A").EntireColumn.Hidden = True
End With
With wb.Sheets("CRqs")
Set searchRange = .Range("G1", .Range("G" & .Rows.Count).End(xlUp))
End With
Set Scwb = Workbooks.Open("https://******.sharepoint.com/sites/******/Shared%20Documents/General/NAA.xlsx") 'Opens the doc that I am looking to paste the data in
Set dRow = Scwb.Sheets("AppAccs").Cells(Scwb.Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Set foundCell = searchRange.Find(what:=mysearch, Lookat:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not foundCell Is Nothing Then
foundCell.Offset(0, 6).Value = "Yes"
foundCell.Offset(0, -6).EntireRow.Copy _ 'this works copying the source row of data from a reference entered (mysearch)
dRow ' this now fails with a runtime error 1004
Else
MsgBox "We cannot find the ID " & mysearch & " to send. Please check ID."
End If
Application.DisplayAlerts = True
End Sub
If anyone can help or needs any further info please let me know. Thanks,
I'm creating a script to import data from a series of Workbooks in a declared folder.
The Workbook may contain multiple sheets as dictated by the values on the "DD Meeting" tab, whereby if the cell value begins with "Code_", there will be no sheet to import from.
I'm trying to create a script that looks for a sheet name based on these values, copies the data, then looks for the next sheet to resume the copy job.
I can copy from the first sheet fine, however the script then has trouble searching for the next sheet name using an activecell instead of the declaring a specific cell (I need to offset hence can't name the cell).
This works:
Set wsData = wb.Sheets(Worksheets("DD Meeting").Range("D6").Value)
This doesnt:
Set wsData = wb.Sheets(Worksheets("DD Meeting").ActiveCell.Value)
Any help is appreciated, thanks.
Sub ImportInfo()
Dim sPath As String 'path of folder containing info
Dim sFileName As String '
Dim wsSummary As Worksheet 'worksheet to paste data to in this workbook
Dim wsData As Worksheet 'sheet with data to copy
Dim wb As Workbook 'workbooks to loop thorugh
Dim nr As Long 'next row to add the data
'Get the worksheet to add the info to
Set wsSummary = ThisWorkbook.Worksheets("Sheet1")
'first row is 2
nr = 2
sPath = "C:\Users\sthorley\Downloads\Test\" '[COLOR=#ff0000][B]Change as required[/B][/COLOR]
sFileName = Dir(sPath & "*.xlsm")
Do While sFileName <> ""
'open workbook
Set wb = Workbooks.Open(Filename:=sPath & sFileName, ReadOnly:=True)
wb.Sheets(Worksheets("DD Meeting").Range("D6").Value).Activate
'get the sheet to copy from
Set wsData = wb.Sheets(Worksheets("DD Meeting").Range("D6").Value)
Worksheets("DD Meeting").Select
Worksheets("DD Meeting").Range("D6").Select
'get the data
Do While ActiveCell.Value <> "*Code*"
wsSummary.Range("A" & nr).Value = wsData.Range("B5").Value
wsSummary.Range("B" & nr).Value = wsData.Range("B3").Value
wsSummary.Range("C" & nr).Value = sFileName
wsData.Activate
wsData.Range("A5").Select
' Summary Key Points
wsData.Cells.Find(What:="Summary/Key points", After:=ActiveCell, LookIn:= _
xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext _
, MatchCase:=False, SearchFormat:=False).Activate
wsSummary.Range("D" & nr).Value = ActiveCell.Offset(2).Value
'get next row
nr = nr + 1
Worksheets("DD Meeting").Select
ActiveCell.Offset(1).Select
'get the sheet to copy from
Set wsData = Nothing
Set wsData = wb.Sheets(Worksheets("DD Meeting").ActiveCell.Value)
Loop
'close the workbook
wb.Close savechanges:=False
'get next workbook name
sFileName = Dir
Loop
End Sub
I have used bits and pieces of code on forums to create a macro that exports PDF's from a single sheet in excel. Each PDF contains the header and all relevant rows to the employee (all rows with employee ID). When I run it all goes well and the pdfs are correct, however the macro never stops running.
I believe I have created an infinite loop and am not sure how to correct it.
It also creates a PDF just containing the header that is not necessary.
Sub PracticeToPDF()
Dim ws As Worksheet
Dim ws_unique As Worksheet
Dim DataRange As Range
Dim iLastRow As Long
Dim iLastRow_unique As Long
Dim UniqueRng As Range
Dim Cell As Range
Dim LastRow As Long
Dim LastColumn As Long
Application.ScreenUpdating = False
'Note that the macro will save the pdf files in this active directory so you should save in an appropriate folder
DirectoryLocation = ActiveWorkbook.Path
Set ws = Worksheets("BootVSPayroll") 'Amend to reflect the sheet you wish to work with
Set ws_unique = Worksheets("BootVSPayroll") 'Amend to reflect the sheet you wish to work with
'Find the last row in each worksheet
iLastRow = ws.Cells(Rows.Count, "A").End(xlUp).Row
iLastRow_unique = ws_unique.Cells(Rows.Count, "A").End(xlUp).Row
With ws
'I've set my range to reflect my headers which are fixed for this report
Set DataRange = ws.Range("$A$1:$K$1" & iLastRow)
'autofilter field is 4 as I want to print based on the practice value in column D
DataRange.AutoFilter Field:=1
Set UniqueRng = ws_unique.Range("A1:A20" & iLastRow_unique)
For Each Cell In UniqueRng
DataRange.AutoFilter Field:=1, Criteria1:=Cell
Name = DirectoryLocation & "\" & Cell.Value & " BOOT Report" & ".pdf"
ws.ExportAsFixedFormat Type:=xlTypePDF, Filename:=Name _
, Quality:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas _
:=False, OpenAfterPublish:=False
Next Cell
End With
With ws
.Protect Userinterfaceonly:=True, _
DrawingObjects:=False, Contents:=True, Scenarios:= _
True, AllowFormattingColumns:=True, AllowFormattingRows:=True
.EnableOutlining = True
.EnableAutoFilter = True
If .FilterMode Then
.ShowAllData
End If
End With
Application.ScreenUpdating = True
End Sub
Did you perhaps mean for:
Set DataRange = ws.Range("$A$1:$K$1" & iLastRow)
...
Set UniqueRng = ws_unique.Range("A1:A20" & iLastRow_unique)
to instead be:
Set DataRange = ws.Range("$A$1:$K$" & iLastRow)
...
Set UniqueRng = ws_unique.Range("A1:A" & iLastRow_unique)
?
If, for example, (taken from ws_unique) your last used row, iLastRow_unique equals 200, then "A1:A20" & iLastRow_unique is equivalent to "A1:A20200" -- which may be a lot more rows that you intended to loop through, I think.
I want to fill in the workbook that holds the macro with data from another workbook. The data I need to copy can be on different columns on the source file, depending on the way this source file is generated. So I may run into a problem, because I might get the data I want on a wrong column, or I may even get data I do not want. So I guess it's better to look for the column header (which are always the same string, no matter how the report is generated). I can use the Find method to search for the headers, but how to copy the rows below each header? The range where I want the data pasted are always the same ranges on the paste workbook, and always the first sheet.
Following is my current code:
Sub Import()
' Looks up for the Source Report file and imports its data into wkbk that holds the macro
On Error Resume Next
' Defines Source Report file variable
Dim SourceFile As Variant
' Opens the SourceFile
MsgBox ("Open the SourceFile")
SourceFile = Application.GetOpenFilename(FileFilter:="Excel Files,*.xl*;*.xm*")
If SourceFile <> False Then
Workbooks.Open Filename:=SourceFile
End If
SourceFileDir = Dir(SourceFile)
' Looks up the last row on SourceFile to copy the entire data later
With Workbooks(SourceFileDir).Worksheets(1)
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
End With
' MsgBox ("The last row of data in the Source File is " & LastRow)
' Sets echo off before copying
Application.ScreenUpdating = False
' Copies SourceFile data into paste file, the one that holds the macro
' Serial Number
Workbooks(SourceFileDir).Worksheets(1).Range("E7:E" & LastRow).Copy
ThisWorkbook.Worksheets(1).Range("A38").PasteSpecial xlPasteValues
' Product ID
Workbooks(SourceFileDir).Worksheets(1).Range("A7:A" & LastRow).Copy
ThisWorkbook.Worksheets(1).Range("B38").PasteSpecial xlPasteValues
' Gets out of copy mode
Application.CutCopyMode = False
' Sets echo back on
Application.ScreenUpdating = True
End Sub
The total number of columns I need is 9, the code above just shows two of them, Serial Number and Product ID.
Thanks for your help.
Workbook to Workbook
Adjust the values in the constants section and right below in the Headers array.
Option Explicit
Sub Import()
' Looks up for the Source Report file and imports its data into
' wkbk that holds the macro
Const LastRowColumnS As Long = 1
Const FirstRowS = 7
Const FirstRowP = 38
Dim Headers As Variant
Headers = Array("Serial Number", "Product ID", "ID", _
"Name4", "Name5", "Name6", _
"Name7", "Name8", "Name9")
Dim rng As Range
Dim SourceFile As Variant
Dim wsS As Worksheet
Dim wsP As Worksheet
Dim LastRowS As Long
Dim CurColS As Long
Dim CurColP As Long
Dim NumberOfRows As Long
Dim Count As Long
Dim i As Long
' Opens Source File.
MsgBox ("Open the SourceFile")
SourceFile = Application.GetOpenFilename( _
FileFilter:="Excel Files,*.xl*;*.xm*")
If SourceFile <> False Then
Workbooks.Open Filename:=SourceFile
Else
MsgBox "You selected cancel."
Exit Sub
End If
' Define worksheets.
Set wsS = ActiveWorkbook.Worksheets(1)
Set wsP = ThisWorkbook.Worksheets(1)
' Define last cell with data in Last Row Column of Source Sheet.
Set rng = wsS.Columns(LastRowColumnS).Find( _
What:="*", LookIn:=xlFormulas, SearchDirection:=xlPrevious)
If rng Is Nothing Then
MsgBox "No data in column."
Exit Sub
End If
NumberOfRows = rng.Row - FirstRowS + 1
For i = 0 To UBound(Headers)
' Define column of Current Header in Source Sheet.
Set rng = wsS.Cells.Find(What:=Headers(i), _
After:=wsS.Cells(wsS.Rows.Count, wsS.Columns.Count), _
LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows)
If Not rng Is Nothing Then
CurColS = rng.Column
' Define column of Current Header in Paste Sheet.
Set rng = wsP.Cells.Find(What:=Headers(i), _
After:=wsP.Cells(wsP.Rows.Count, wsP.Columns.Count), _
LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows)
If Not rng Is Nothing Then
CurColP = rng.Column
' Write data from Source Sheet to Paste Sheet.
wsP.Cells(FirstRowP, CurColP).Resize(NumberOfRows).Value _
= wsS.Cells(FirstRowS, CurColS).Resize(NumberOfRows).Value
' Count the transfer.
Count = Count + 1
End If
End If
Next i
' Maybe close Source Workbook.
'wsS.Parent.Close False
MsgBox "Transferred data from '" & Count & "' columns."
End Sub
EDIT:
Since some of the headers have different values (names) on each sheet you should use two arrays (one for each sheet) and adjust the values appropriately:
Option Explicit
Sub Import()
' Looks up for the Source Report file and imports its data into
' wkbk that holds the macro
Const LastRowColumnS As Long = 1
Const FirstRowS = 7
Const FirstRowP = 38
Dim HeadSource As Variant
Dim HeadPaste As Variant
HeadSource = Array("Serial Number", "Product ID", "ID", _
"Name4", "Name5", "Name6", _
"Name7", "Name8", "Name9")
HeadPaste = Array("Serial Number", "Product ID", "ID", _
"Name4", "Name5", "Name6", _
"Name7", "Name8", "Name9")
Dim rng As Range
Dim SourceFile As Variant
Dim wsS As Worksheet
Dim wsP As Worksheet
Dim LastRowS As Long
Dim CurColS As Long
Dim CurColP As Long
Dim NumberOfRows As Long
Dim Count As Long
Dim i As Long
' Opens Source File.
MsgBox ("Open the SourceFile")
SourceFile = Application.GetOpenFilename( _
FileFilter:="Excel Files,*.xl*;*.xm*")
If SourceFile <> False Then
Workbooks.Open Filename:=SourceFile
Else
MsgBox "You selected cancel."
Exit Sub
End If
' Define worksheets.
Set wsS = ActiveWorkbook.Worksheets(1)
Set wsP = ThisWorkbook.Worksheets(1)
' Define last cell with data in Last Row Column of Source Sheet.
Set rng = wsS.Columns(LastRowColumnS).Find( _
What:="*", LookIn:=xlFormulas, SearchDirection:=xlPrevious)
If rng Is Nothing Then
MsgBox "No data in column."
Exit Sub
End If
NumberOfRows = rng.Row - FirstRowS + 1
For i = 0 To UBound(HeadSource)
' Define column of Current Header in Source Sheet.
Set rng = wsS.Cells.Find(What:=HeadSource(i), _
After:=wsS.Cells(wsS.Rows.Count, wsS.Columns.Count), _
LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows)
If Not rng Is Nothing Then
CurColS = rng.Column
' Define column of Current Header in Paste Sheet.
Set rng = wsP.Cells.Find(What:=HeadPaste(i), _
After:=wsP.Cells(wsP.Rows.Count, wsP.Columns.Count), _
LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows)
If Not rng Is Nothing Then
CurColP = rng.Column
' Write data from Source Sheet to Paste Sheet.
wsP.Cells(FirstRowP, CurColP).Resize(NumberOfRows).Value _
= wsS.Cells(FirstRowS, CurColS).Resize(NumberOfRows).Value
' Count the transfer.
Count = Count + 1
End If
End If
Next i
' Maybe close Source Workbook.
'wsS.Parent.Close False
MsgBox "Transferred data from '" & Count & "' columns."
End Sub
I have checked a bunch of different posts and can't seem to find the exact code I am looking for. Also I have never used VBA before so I'm trying to take codes from other posts and input my info for it to work. No luck yet. At work we have a payroll system in Excel. I am trying to search for my name "Clarke, Matthew" and then copy that row and paste it to the workbook I have saved on my desktop "Total hours".
CODE
Sub Sample()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim copyFrom As Range
Dim lRow As Long '<~~ Not Integer. Might give you error in higher versions of excel
Dim strSearch As String
Set wb1 = ThisWorkbook
Set ws1 = wb1.Worksheets("yourSheetName")
strSearch = "Clarke, Matthew"
With ws1
'~~> Remove any filters
.AutoFilterMode = False
'~~> I am assuming that the names are in Col A
'~~> if not then change A below to whatever column letter
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("A1:A" & lRow)
.AutoFilter Field:=1, Criteria1:="=*" & strSearch & "*"
Set copyFrom = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
'~~> Remove any filters
.AutoFilterMode = False
End With
'~~> Destination File
Set wb2 = Application.Workbooks.Open("C:\Sample.xlsx")
Set ws2 = wb2.Worksheets("Sheet1")
With ws2
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lRow = 1
End If
copyFrom.Copy .Rows(lRow)
End With
wb2.Save
wb2.Close
End Sub
SNAPSHOT
Expanding on what timrau said in his comment, you can use the AutoFilter function to find the row with your name in it. (Note that I'm assuming you have the source workbook open)
Dim curBook As Workbook
Dim targetBook As Workbook
Dim curSheet As Worksheet
Dim targetSheet As Worksheet
Dim lastRow As Integer
Set curBook = ActiveWorkbook
Set curSheet = curBook.Worksheets("yourSheetName")
'change the Field number to the correct column
curSheet.Cells.AutoFilter Field:=1, Criteria1:="Clarke, Matthew"
'The Offset is to remove the header row from the copy
curSheet.AutoFilter.Range.Offset(1).Copy
curSheet.ShowAllData
Set targetBook = Application.Workbooks.Open "PathTo Total Hours"
Set targetSheet = targetBook.WorkSheet("DestinationSheet")
lastRow = Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).row
targetSheet.Cells(lastRow + 1, 1).PasteSpecial
targetBook.Save
targetBook.Close
As you can see I put placeholders in for the specific setup of your workbook.
I know this is old, but for anyone else searching for how to do this, it can be done in a much more direct fashion:
Public Sub ExportRow()
Dim v
Const KEY = "Clarke, Matthew"
Const WS = "Sheet1"
Const OUTPUT = "c:\totalhours.xlsx"
Const OUTPUT_WS = "Sheet1"
v = ThisWorkbook.Sheets(WS).Evaluate("index(a:xfd,match(""" & KEY & """,a:a,),)")
With Workbooks.Open(OUTPUT).Sheets(OUTPUT_WS)
.[1:1].Offset(.[counta(a:a)]) = v
.Parent.Save: .Parent.Close
End With
End Sub