Copy entire row from one workbook to another - excel

I need a macro that can copy the entire row from the workbook I am in based on the cell I have selected. I can do this already, using the following:
ActiveCell.EntireRow.Select
Selection.Copy
But then, I need it to paste that (formatting and all) into the first empty row (based on column B) of a workbook that is closed. R:\dasboards\wo.xlsm

Backup Entire Row to a Closed Workbook
Adjust the values in the constants section.
Option Explicit
Sub BackupEntireRow()
Const dFilePath As String = "R:\DashBoards\wo.xlsm"
Const dwsName As String = "Sheet1"
Const dlrCol As String = "B"
Dim IsSuccess As Boolean
If TypeName(Selection) <> "Range" Then
MsgBox "No cells selected.", vbCritical
Exit Sub
End If
Dim dwbName As String: dwbName = Dir(dFilePath)
If Len(dwbName) = 0 Then
MsgBox "Could not find the destination file" _
& vbLf & "'" & dFilePath & "'", vbCritical
Exit Sub
End If
Dim srrg As Range: Set srrg = ActiveCell.EntireRow
Dim dwb As Workbook
Dim dDoCloseWorkbook As Boolean
On Error Resume Next
Set dwb = Workbooks(dwbName)
On Error GoTo 0
If dwb Is Nothing Then
Set dwb = Workbooks.Open(dFilePath)
dDoCloseWorkbook = True
End If
Dim dws As Worksheet
On Error Resume Next
Set dws = dwb.Worksheets(dwsName)
On Error GoTo 0
If dws Is Nothing Then
If dDoCloseWorkbook Then
dwb.Close SaveChanges:=False
End If
MsgBox "The destination worksheet '" & dwsName & "' doesn't exist.", _
vbCritical
Exit Sub
End If
Dim dCell As Range
Set dCell = dws.Cells(dws.Rows.Count, dlrCol).End(xlUp).Offset(1)
Dim drrg As Range: Set drrg = dCell.EntireRow
srrg.Copy drrg
If dDoCloseWorkbook Then
dwb.Close SaveChanges:=True
Else
dwb.Save
End If
IsSuccess = True
If IsSuccess Then
MsgBox "Row backed up.", vbInformation
End If
End Sub

Related

Creating worksheets and naming them with the values in a list/table [duplicate]

This question already has answers here:
Test or check if sheet exists
(23 answers)
Closed 2 months ago.
I am trying to create multiple worksheet in a workbook and name them based on a contents in a particular table. I am doing this as the list can be dynamic and might need to create more/less sheets depending on the requirement.
Sub CreateSheetsFromList()
Dim NewSheet As Worksheet
Dim x As Integer
Dim tbl As ListObject
Dim cell As Range
Application.ScreenUpdating = False
Set tbl = Worksheets("Sheet1").ListObjects("Table1")
For Each cell In tbl.DataBodyRange.Cells
If SheetExists(cell.Value) = False And cell.Value <> "" Then
Set NewSheet = Sheets.Add(after:=Sheets(Sheets.Count))
NewSheet.Name = cell.Value
End If
Next cell
Application.ScreenUpdating = True
End Sub
Function SheetExists(SheetName As String) As Boolean
Dim sht As Worksheet
On Error Resume Next
Set sht = ActiveWorkbook.Worksheets("Sheet1")
On Error GoTo 0
If Not sht Is Nothing Then SheetExists = True
Set sht = Nothing
End Function
Unable to get any kind of results. Please let me know if there is a way to do this in an optimized manner
You have to use the passed variable to check - not a fixed value ("Sheet1"):
Function SheetExists(SheetName As String) As Boolean
Dim sht As Worksheet
On Error Resume Next
'Use the passed SheetName to test for
Set sht = ActiveWorkbook.Worksheets(SheetName)
On Error GoTo 0
If Not sht Is Nothing Then SheetExists = True
End Function
Add Sheets From Excel Table (ListObject)
Utilization
Sub AddSheetsFromListObjectTEST()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
AddSheetsFromListObject wb, "Sheet1", "Table1", 1
End Sub
The Method
Sub AddSheetsFromListObject( _
ByVal wb As Workbook, _
ByVal WorksheetID As Variant, _
ByVal ListObjectID As Variant, _
ByVal ListColumnID As Variant)
Const PROC_TITLE As String = "Create Sheets From ListObject"
On Error GoTo ClearError
Dim sws As Worksheet: Set sws = wb.Sheets(WorksheetID)
Dim slo As ListObject: Set slo = sws.ListObjects(ListObjectID)
Dim slc As ListColumn: Set slc = slo.ListColumns(ListColumnID)
Dim srg As Range: Set srg = slc.DataBodyRange
Dim dws As Worksheet, sCell As Range, dName As String, NotRenamed As Boolean
For Each sCell In srg.Cells
dName = CStr(sCell.Value)
If dws Is Nothing Then
Set dws = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
End If
On Error GoTo RenameError
dws.Name = dName
On Error GoTo ClearError
If NotRenamed Then NotRenamed = False Else Set dws = Nothing
Next sCell
If Not dws Is Nothing Then
Application.DisplayAlerts = False
dws.Delete
Application.DisplayAlerts = True
End If
ProcExit:
Exit Sub
RenameError:
'Debug.Print "Name = """ & dName & """" & vbLf & Left(Err.Description, 48)
NotRenamed = True
Resume Next
ClearError:
MsgBox "Run-time error '" & Err.Number & "':" & vbLf & vbLf _
& Err.Description, vbCritical, PROC_TITLE
Resume ProcExit
End Sub

Execute Time (Select, Copy & Paste in same order for Non Adjacent Cells)

This VBA takes a lot of time to execute
Sub test()
Dim IB As String
Dim copyRng As Range, cel As Range, pasteRng As Range
With Selection
Set copyRng = Selection
End With
IB = Application.InputBox("Enter Exact Sheet Name to Paste")
Set pasteRng = Sheets(IB).Range("A1")
For Each cel In copyRng
cel.Copy
pasteRng.Range(cel.Address).PasteSpecial xlPasteAll
Next
Application.CutCopyMode = False
End Sub
Copy Non-Contiguous Ranges
I've turned off screen updating and replaced looping through cells with looping through areas of the range.
When you would only need values to be copied, another (vast) improvement in performance would be to copy by assignment. Then in the loop, you would use the following code:
darg.Value = sarg.Value
instead of sarg.Copy darg.
Option Explicit
Sub CopyNonContiguous()
Const ProcTitle As String = "Copy Non-Contiguous"
Dim srg As Range
If TypeName(Selection) = "Range" Then
Set srg = Selection
Else
MsgBox "Select a range. please.", vbCritical, ProcTitle
Exit Sub
End If
Dim wsName As Variant
wsName = Application.InputBox( _
"Enter Sheet Name to Paste", ProcTitle, , , , , , 2)
If wsName = False Then
MsgBox "You canceled.", vbExclamation, ProcTitle
Exit Sub
End If
Dim dws As Worksheet
On Error Resume Next
Set dws = ActiveWorkbook.Worksheets(wsName) ' consider 'ThisWorkbook'
On Error GoTo 0
If dws Is Nothing Then
MsgBox "The worksheet '" & wsName & "' doesn't exist.", _
vbCritical, ProcTitle
Exit Sub
End If
Application.ScreenUpdating = False
Dim sarg As Range
Dim darg As Range
For Each sarg In srg.Areas
Set darg = dws.Range(sarg.Address)
sarg.Copy darg
Next sarg
Application.ScreenUpdating = True
MsgBox "Cells copied.", vbInformation, ProcTitle
End Sub

Copy a column by name from multiple Excel files which are saved in a specific folder and save it in csv

I'm trying to copy a column from all the Excel files(.xls) saved in a specific folder and append to a text file.
Selecting the column should be based on the column name, as the column number varies for every Excel file.
How can I create the script with this condition?
Stack Columns
This will copy the columns' values to a new (destination) workbook and save the workbook in the same folder as the folder of the workbook containing this code (Thisworkbook). The new workbook is named after the header (Name.csv).
An improvement would be to write the values to a data structure (array, dictionary, or array list) and afterward to write its values to a text file in one go without ever having a destination workbook.
Adjust the values in the constants section.
Option Explicit
Sub StackColumns()
' Needs 'RefWorksheet', 'RefFirstOccurrenceInRow' and 'RefColumnDataRange'
Const ProcTitle As String = "Stack Columns"
' Source
Const sFolderPath As String = "C:\Test\"
Const sFilePattern As String = "*.xls*"
Const swsName As String = "Sheet1"
Const sHeader As String = "Name"
Const shRow As Long = 1
' Destination
Dim dFolderPath As String: dFolderPath = ThisWorkbook.Path & "\"
Dim dBaseName As String: dBaseName = sHeader
Dim sFileName As String: sFileName = Dir(sFolderPath & sFilePattern)
If Len(sFileName) = 0 Then
MsgBox "No files found.", vbCritical, ProcTitle
Exit Sub
End If
Dim swb As Workbook
Dim sws As Worksheet
Dim shCell As Range ' Header Cell
Dim scdtrg As Range ' Column Data Range (no headers)
Dim dwb As Workbook
Dim dws As Worksheet
Dim dCell As Range
Dim IsDestinationWorkbookAdded As Boolean
Application.ScreenUpdating = False
Do Until Len(sFileName) = 0
Set swb = Workbooks.Open(sFolderPath & sFileName)
Set sws = RefWorksheet(swb, swsName)
If Not sws Is Nothing Then ' worksheet found
Set shCell = RefFirstOccurrenceInRow(sws.Rows(shRow), sHeader)
If Not shCell Is Nothing Then ' header found
Set scdtrg = RefColumnDataRange(shCell)
If Not scdtrg Is Nothing Then ' found data in Column Data Range
If Not IsDestinationWorkbookAdded Then ' not yet added
Set dwb = Workbooks.Add(xlWBATWorksheet)
Set dws = Worksheets(1)
Set dCell = dws.Range("A1")
IsDestinationWorkbookAdded = True
'Else ' already added
End If
dCell.Resize(scdtrg.Rows.Count).Value = scdtrg.Value
Set dCell = dCell.Offset(scdtrg.Rows.Count)
Set scdtrg = Nothing
'Else ' no data in Column Data Range
End If
Set shCell = Nothing
'Else ' header not found
End If
Set sws = Nothing
'Else ' worksheet not found
End If
swb.Close False
sFileName = Dir
Loop
If Not dwb Is Nothing Then
Application.DisplayAlerts = False ' overwrite without confirmation
dwb.SaveAs dFolderPath & dBaseName & ".csv", xlCSV
Application.DisplayAlerts = True
'dwb.FollowHyperlink dFolderPath ' explore the Destination Path
'dwb.Close
End If
Application.ScreenUpdating = True
MsgBox "Columns stacked.", vbInformation, ProcTitle
End Sub
Function RefWorksheet( _
ByVal wb As Workbook, _
ByVal WorksheetName As String) _
As Worksheet
On Error Resume Next
Set RefWorksheet = wb.Worksheets(WorksheetName)
On Error GoTo 0
End Function
Function RefFirstOccurrenceInRow( _
ByVal RowRange As Range, _
ByVal SearchString As String) _
As Range
On Error GoTo ClearError
With RowRange.Rows(1)
Set RefFirstOccurrenceInRow _
= .Find(SearchString, .Cells(.Cells.Count), xlFormulas, xlWhole)
End With
ProcExit:
Exit Function
ClearError:
Resume ProcExit
End Function
Function RefColumnDataRange( _
ByVal HeaderCell As Range) _
As Range
On Error GoTo ClearError
With HeaderCell.Cells(1)
With .Resize(.Worksheet.Rows.Count - .Row).Offset(1)
Dim lCell As Range
Set lCell = .Find("*", , xlFormulas, , , xlPrevious)
Set RefColumnDataRange = .Resize(lCell.Row - .Row + 1)
End With
End With
ProcExit:
Exit Function
ClearError:
Resume ProcExit
End Function

Object Doesn't Support this Property or Method When copying from another workbook

I'm trying to write a small code in Excel that lets me open in the background another workbook, copy a range of data in there, and then pasty it in the active workboo. Should be pretty straight forward but for some reason I'm getting this error. So far what I've got is this, and I know the error comes from this line "cpyLastRow = ImportBook.cpySheet.Cells(3, 1).End(xlDown).Row", Ive got some variables commented to make it a little bit mor dyanimc in the future. Any ideas?
Private Sub CommandButton2_Click()
Dim OpenFile As Variant
Dim ImportBook As Workbook
Dim cpySheet As Worksheet
Dim cpyLastRow As Long
Dim cpyLastColumn As Long
'Dim cpyStartCell As Range
Set cpySheet = Sheets("DAO")
'Set cpyStartCell = Range("C3")
Application.ScreenUpdating = False
OpenFile = Application.GetOpenFilename(Title:="Select a file to import data", filefilter:="Excel Files (*.xls*),*xls*")
If OpenFile <> False Then
Set ImportBook = Application.Workbooks.Open(OpenFile)
cpyLastRow = ImportBook.cpySheet.Cells(3, 1).End(xlDown).Row
'cpyLastColumn = cpyStartCell.Column
ImportBook.cpySheet.Range("C3", cpySheet.Cells(cpyLastRow, 3)).Copy
ThisWorkbook.ActiveSheet.Range("C3").PasteSpecial xlPasteValues
ImportBook.Close False
End If
Application.ScreenUpdating = True
End Sub
You get an error due to mixing import workbook property and active worbook sheet reference. Try to use method 1 or method 2. Be sure to specify actual sheet name in the import workbook.
'get reference to sheet "ABF - DAO" in active workbook
Set cpySheet = Sheets("ABF - DAO")
...
'error: mix workbook property and sheet reference
cpyLastRow = ImportBook.cpySheet.Cells(3, 1).End(xlDown).Row
'method 1: get reference to sheet in import workbook
Set cpySheet = ImportBook.Sheets("ABF - DAO")
cpyLastRow = cpySheet.Cells(3, 1).End(xlDown).Row
'method 2: get last row without sheet reference
cpyLastRow = ImportBook.Sheets("ABF - DAO")
Copy Column Range From Closed Workbook
Option Explicit
Private Sub CommandButton2_Click()
Const ProcName As String = "CommandButton2_Click"
On Error GoTo clearError
Const sTitle As String = "Select a file to import data"
Const sFilter As String = "Excel Files (*.xls*),*xls*"
Const sName As String = "DAO"
Const sFirst As String = "C3"
Const dFirst As String = "C3"
Dim dSuccess As Boolean
' Source
' Path
Dim sPath As Variant
sPath = Application.GetOpenFilename(Title:=sTitle, FileFilter:=sFilter)
If sPath = False Then
MsgBox "You canceled.", vbExclamation, "Canceled"
GoTo ProcExit
End With
Application.ScreenUpdating = False
' Worksheet
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
On Error Resume Next
Dim sws As Worksheet: Set sws = swb.Worksheets(sName)
On Error GoTo 0
If sws Is Nothing Then
CloseWithoutSaving swb
MsgBox "The worksheet '" & sName & "' does not exist.", _
vbCritical, "No Worksheet"
GoTo ProcExit
End If
' Range
Dim fCell As Range: Set fCell = sws.Range(sFirst)
With fCell
Dim lCell As Range
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then
CloseWithoutSaving swb
MsgBox "No data.", vbCritical, "No Data"
GoTo ProcExit
End If
Dim srg As Range: Set srg = .Resize(lCell.Row - .Row + 1)
End With
' Destination
' Assuming that the button is on the Destination Worksheet.
Dim dCell As Range: Set dCell = Range(dFirst)
' Otherwise, you should do something like this:
'Set dCell = ThisWorkbook.Worksheets("DAO").Range(dFirst)
' Copy (by Assignment)
dCell.Resize(srg.Rows.Count).Value = srg.Value
CloseWithoutSaving swb
dSuccess = True
ProcExit:
If Not Application.ScreenUpdating Then
Application.ScreenUpdating = True
End If
If dSuccess Then
MsgBox "Data transferred.", vbInformation, "Success"
End If
Exit Sub
clearError:
Debug.Print "'" & ProcName & "': Unexpected Error!" & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
Resume ProcExit
End Sub
Sub CloseWithoutSaving( _
ByVal wb As Workbook)
Application.DisplayAlerts = False
wb.Close False
Application.DisplayAlerts = True
End Sub

Remove duplicate rows in Excel from a particular sheet

Thanks in advance for helping!
I am currently using the below code to populate multiple .csv files into one sheet and then hide the sheet. The help I need is to remove duplicate rows from that sheet. Can it be incorporated into this code? Thank you!
Sub ImportCSVsWithReference()
'UpdatedforSPSS
Dim xSht As Worksheet
Dim xWb As Workbook
Dim xStrPath As String
Dim xFileDialog As FileDialog
Dim xFile As String
On Error GoTo ErrHandler
Set xFileDialog = Application.FileDialog(msoFileDialogFolderPicker)
xFileDialog.AllowMultiSelect = False
xFileDialog.Title = "Select the folder with the csv files [File Picker]"
If xFileDialog.Show = -1 Then
xStrPath = xFileDialog.SelectedItems(1)
End If
If xStrPath = "" Then Exit Sub
Set xSht = Sheets.Add
ActiveSheet.Name = "ImportedData"
Worksheets("ImportedData").Visible = False
Application.ScreenUpdating = False
xFile = Dir(xStrPath & "\" & "*.csv")
Do While xFile <> ""
Set xWb = Workbooks.Open(xStrPath & "\" & xFile)
ActiveSheet.UsedRange.Copy xSht.Range("A" & Rows.Count).End(xlUp).Offset(1)
xWb.Close False
xFile = Dir
Loop
Application.ScreenUpdating = True
Exit Sub
ErrHandler:
MsgBox "Encountered an error. Try again", , "Error"
End Sub
There is actually a built-in function to remove duplicates from a range. It is called RemoveDuplicates...
Let's look at an example. I assume here that -
The table has 3 columns
The table has 100 rows
The table does not have a header line
Then the code to remove duplicates will look something like:
ActiveSheet.Range("A1:C100").RemoveDuplicates Columns:=Array(1, 2, 3), Header:=xlNo
See the docs at https://learn.microsoft.com/en-us/office/vba/api/excel.range.removeduplicates
Do Not Import Headers After the First Imported Worksheet
s - Source (read from)
d - Destination (written to)
The Code
Option Explicit
Sub ImportCSVsWithReference()
Const ProcName As String = "ImportCSVsWithReference"
'On Error GoTo clearError
Const WorksheetName As String = "ImportedData"
Const HeaderRows As Long = 1
' Get Folder Path.
Dim FolderPath As String
Dim fd As Office.FileDialog
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
With fd
.AllowMultiSelect = False
'.InitialFileName = "C:\Test" ' consider using this
.Title = "Select the folder with the csv files [File Picker]"
If .Show = -1 Then
FolderPath = .SelectedItems(1)
Else
GoTo ProcExit ' Exit Sub
End If
End With
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Application.ScreenUpdating = False
' Define Destination Worksheet (delete existing, add new).
On Error Resume Next
Dim dws As Worksheet: Set dws = dwb.Worksheets(WorksheetName)
On Error GoTo 0
If Not dws Is Nothing Then ' it already exists
Application.DisplayAlerts = False
dws.Delete ' delete without confirmation
Application.DisplayAlerts = True
End If
Set dws = dwb.Worksheets.Add(After:=dwb.Sheets(dwb.Sheets.Count)) ' Sheets!
dws.Name = WorksheetName
dws.Visible = xlSheetHidden ' xlSheetVeryHidden (a 'tougher' option)
' Define Destination Cell.
Dim dCell As Range: Set dCell = dws.Range("A1")
' Copy data from Source Worksheets to Destination Worksheet.
Dim FileName As String: FileName = Dir(FolderPath & "\" & "*.csv")
Dim sws As Worksheet
Dim srg As Range
Dim swsCount As Long
Do While FileName <> ""
' There is only one worksheet in a csv file (the first):
Set sws = Workbooks.Open(FolderPath & "\" & FileName).Worksheets(1)
Set srg = sws.UsedRange
If srg.Rows.Count > HeaderRows Then
swsCount = swsCount + 1
If swsCount > 1 Then ' headers for the first worksheet only
Set srg = srg.Resize(srg.Rows.Count - HeaderRows) _
.Offset(HeaderRows)
End If
dCell.Resize(srg.Rows.Count, srg.Columns.Count).Value _
= srg.Value
Set dCell = dCell.Offset(srg.Rows.Count)
End If
sws.Parent.Close False ' the workbook is the 'parent' of the worksheet
FileName = Dir
Loop
'dwb.save
ProcExit:
If Application.ScreenUpdating = False Then
Application.ScreenUpdating = True
End If
' Inform.
Select Case swsCount
Case 0
MsgBox "No worksheet imported.", vbExclamation, "Fail?"
Case 1
MsgBox "1 worksheet imported.", vbInformation, "Success"
Case Else
MsgBox swsCount & " worksheets imported.", vbInformation, "Success"
End Select
Exit Sub
clearError:
MsgBox "'" & ProcName & "': Unexpected Error!" & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
Resume ProcExit
End Sub

Resources