Empty rows in file generated from macros in excel - excel

I am trying to split a file with 120 records into files of at-most 50 records each. So expectation is it should genarate 2 files with 50 records and 1 file wit 20 but what I am getting is 3 files of 51 records with 1 empty file in the end for first 2 and 31 empty lines in 3rd file.
Sub SplitAndSaveFile()
Dim myRow As Long, myBook As Workbook, splitCount As Integer, thisWBName As String, splitCountStr As String, spaceRange As Range
lastRow = ThisWorkbook.Sheets("Data").Cells(rows.Count, 1).End(xlUp).Row
splitCount = 1
splitCountStr = CStr(splitCount)
thisWBName = Replace(ThisWorkbook.Name, ".xlsm", "") + "_Part"
For myRow = 4 To lastRow Step 50
Set myBook = Workbooks.Add
ThisWorkbook.Sheets("Data").rows(myRow & ":" & myRow + 49).EntireRow.Copy myBook.Sheets("Sheet1").Range("A1")
myBook.SaveAs (ThisWorkbook.Path + "\" + thisWBName + splitCountStr + ".txt"), FileFormat:=xlText
myBook.Close
splitCount = splitCount + 1
splitCountStr = CStr(splitCount)
Next myRow
MsgBox ("File(s) generated.")
End Sub

Export Data by Number of Rows
A Partial Quick Fix
Your code seemed to work fine on my testing data, so the only thing I could think of, considering your description of the issue, was that in column A there are formulas evaluating to an empty string at the bottom, which you don't want to include. To fix this, you could use the Find method:
Dim LastRow As Long: LastRow = ThisWorkbook.Worksheets("Data") _
.Columns("A").Find("*", , xlValues, , , xlPrevious)
Unfortunately, you also didn't consider the case when there will be fewer than 50 records to be copied to the last workbook. See how it is handled in the 'In-Depth' solution.
In Depth
This will export the records in a worksheet to new workbooks, saved as text, containing maximally 50 rows.
Option Explicit
Sub SplitAndSaveFile()
Const ProcName As String = "SplitAndSaveFile"
Dim dwbCount As Long ' Generated Workbooks Count
On Error GoTo ClearError
' Source
Const swsName As String = "Data"
Const sCol As String = "A"
Const sfRow As Long = 4
' Destination
Const dfCellAddress As String = "A1" ' needs to be 'A' since entire rows.
Const dMaxRows As Long = 50
Const dNameSuffix As String = "_Part"
' In the loop, this will be replaced by a number ('dwbCount').
Const dIdPlaceHolder As String = "?" ' the '?' is illegal for file names
' The following two lines are dependent on each other.
Const dFileExtension As String = ".txt"
Dim dFileFormat As XlFileFormat: dFileFormat = xlText
' Create a reference to the source first cell ('sfCell').
Dim swb As Workbook: Set swb = ThisWorkbook
Dim sws As Worksheet: Set sws = swb.Worksheets(swsName)
Dim sfCell As Range: Set sfCell = sws.Cells(sfRow, sCol)
' Calculate the number of records (rows) ('drCount').
' This will find the last non-blank cell i.e. cells containing
' formulas evaluating to an empty string are ignored.
' Make sure that the worksheet is not filtered and there are no hidden
' cells.
Dim slCell As Range
Set slCell = sfCell.Resize(sws.Rows.Count - sfRow + 1) _
.Find("*", , xlValues, , , xlPrevious)
If slCell Is Nothing Then Exit Sub ' no data
Dim slRow As Long: slRow = slCell.Row
' This is the preferred way, but besides a few pros, it behaves like 'End'
' i.e. it will find the last non-empty cell. A cell is not empty
' if it contains a formula evaluating to an empty string ('""'):
' it is blank.
'Dim slCell As Range
'Set slCell = sfCell.Resize(sws.Rows.Count - sfRow + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
'If slCell Is Nothing Then Exit Sub ' no data
'Dim slRow As Long: slRow = slCell.Row
' The classic last row using 'End' will find the last non-empty cell.
'Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, sCol).End(xlUp).Row
Dim drCount As Long: drCount = slRow - sfRow + 1
If drCount < 1 Then Exit Sub ' no data (highly unlikely but...)
' Determine the generic file path (dwbGenericFilePath)
Dim swbBaseName As String: swbBaseName = swb.Name
Dim DotPosition As String: DotPosition = InStrRev(swb.Name, ".")
If DotPosition > 0 Then swbBaseName = Left(swbBaseName, DotPosition - 1)
Dim dwbExtension As String: dwbExtension = dFileExtension
If Left(dwbExtension, 1) <> "." Then dwbExtension = "." & dwbExtension
Dim dwbGenericFilePath As String
dwbGenericFilePath = swb.Path & Application.PathSeparator & swbBaseName _
& dNameSuffix & dIdPlaceHolder & dwbExtension
Application.ScreenUpdating = False
' Additional variables used in the loop.
Dim srg As Range
Dim dwb As Workbook
Dim dws As Worksheet
Dim dfCell As Range
Dim dFilePath As String
Do Until drCount = 0
' Create a reference to the current source range.
If drCount > dMaxRows Then ' all workbooks but the last
Set srg = sfCell.Resize(dMaxRows).EntireRow
Set sfCell = sfCell.Offset(dMaxRows)
drCount = drCount - dMaxRows
Else ' the last workbook
Set srg = sfCell.Resize(drCount).EntireRow
drCount = 0
End If
' Copy the current source range to the current destination range.
dwbCount = dwbCount + 1 ' count the number of generated workbooks
Set dwb = Workbooks.Add(xlWBATWorksheet) ' one worksheet only
Set dws = dwb.Worksheets(1)
Set dfCell = dws.Range(dfCellAddress)
srg.Copy dfCell
' Save and close the current destination workbook.
dFilePath = Replace(dwbGenericFilePath, dIdPlaceHolder, CStr(dwbCount))
Application.DisplayAlerts = False ' overwrite without confirmation
dwb.SaveAs dFilePath, dFileFormat
Application.DisplayAlerts = True
dwb.Close SaveChanges:=False
Loop
ProcExit:
Application.ScreenUpdating = True
Select Case dwbCount
Case 0
MsgBox "No files generated.", vbCritical, ProcName
Case 1
MsgBox "One file generated.", vbInformation, ProcName
Case Else
MsgBox dwbCount & " files generated.", vbInformation, ProcName
End Select
Exit Sub
ClearError:
Debug.Print "'" & ProcName & "' Run-time error '" _
& Err.Number & "':" & vbLf & " " & Err.Description
Resume ProcExit
End Sub

Related

Follow up to splitting a sheet into multiple workbooks

I am trying to modify this code found here.
The code works great, but want to know how to enter column letter instead of number.
I believe it has something to do with this line
sCol = Application.InputBox(aibPrompt, aibtitle, aibDefault, , , , , 1)
but not able to get it to work.
Here is the code as found on the other page.
Option Explicit
Sub ExportToWorkbooks()
Const aibPrompt As String = "Which column would you like to filter by?"
Const aibtitle As String = "Filter Column"
Const aibDefault As Long = 3
Dim dFileExtension As String: dFileExtension = ".xlsx"
Dim dFileFormat As XlFileFormat: dFileFormat = xlOpenXMLWorkbook
Dim dFolderPath As String: dFolderPath = "C:\Users\WalteR01\Desktop\VPN Revalidations\Split by Manager\"
If Right(dFolderPath, 1) <> "\" Then dFolderPath = dFolderPath & "\"
If Len(Dir(dFolderPath, vbDirectory)) = 0 Then Exit Sub ' folder not found
If Left(dFileExtension, 1) <> "." Then dFileExtension = "." & dFileExtension
Application.ScreenUpdating = False
Dim sCol As Variant
sCol = Application.InputBox(aibPrompt, aibtitle, aibDefault, , , , , 1)
If Len(CStr(sCol)) = 0 Then Exit Sub ' no entry
If sCol = False Then Exit Sub ' canceled
Dim sws As Worksheet: Set sws = ActiveSheet
If sws.FilterMode Then sws.ShowAllData
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion
Dim srCount As Long: srCount = srg.Rows.Count
If srCount < 3 Then Exit Sub ' not enough rows
Dim srrg As Range: Set srrg = srg.Rows(1) ' to copy column widths
Dim scrg As Range: Set scrg = srg.Columns(sCol)
Dim scData As Variant: scData = scrg.Value
' Write the unique values from the 1st column to a dictionary.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare ' case insensitive
Dim Key As Variant
Dim r As Long
For r = 2 To srCount
Key = scData(r, 1)
If Not IsError(Key) Then ' exclude error values
If Len(Key) > 0 Then ' exclude blanks
dict(Key) = Empty
End If
End If
Next r
If dict.Count = 0 Then Exit Sub ' only error values and blanks
Erase scData
Dim dwb As Workbook
Dim dws As Worksheet
Dim dfcell As Range
Dim dFilePath As String
Dim DateText As String: DateText = Format(Date, "_mm_yyyy")
For Each Key In dict.Keys
' Add a new (destination) workbook and reference the first cell.
Set dwb = Workbooks.Add(xlWBATWorksheet) ' one worksheet
Set dws = dwb.Worksheets(1)
Set dfcell = dws.Range("A1")
' Copy/Paste
srrg.Copy
dfcell.PasteSpecial xlPasteColumnWidths
srg.AutoFilter sCol, Key
srg.SpecialCells(xlCellTypeVisible).Copy dfcell
sws.ShowAllData
dfcell.Select
' Save/Close
dFilePath = dFolderPath & Key & DateText & dFileExtension ' build the file path
Application.DisplayAlerts = False ' overwrite without confirmation
dwb.SaveAs dFilePath, xlOpenXMLWorkbook
Application.DisplayAlerts = True
dwb.Close SaveChanges:=False
Next Key
sws.AutoFilterMode = False
Application.ScreenUpdating = True
MsgBox "Data exported.", vbInformation
End Sub
I have tried to change the line as stated but no luck. The application inbox is what I need to update but not sure how. This is the page I have been using https://learn.microsoft.com/en-us/office/vba/api/excel.application.inputbox
Dim sCol As Variant
sCol = Application.InputBox(aibPrompt, aibtitle, aibDefault, , , , , 1)
As documented here: https://learn.microsoft.com/en-us/office/vba/api/excel.application.inputbox#:~:text=The%20following%20table%20lists%20the%20values%20that%20can%20be%20passed%20in%20the%20Type%20argument
The last argument controls what type of value(s) can be accepted by the InputBox: 1 = Numeric so you need to swap that out for 2 (Text)
sCol = Application.InputBox(aibPrompt, aibtitle, aibDefault, , , , , 2)
OK now I read down... When you call srg.AutoFilter sCol, Key the first argument to AutoFilter should be the column number in the range to be filtered to which the filter should be applied.
Note if your table doesn't start in ColA there needs to be some adjustment, but if it does you could use Cells(1, sCol).Column to convert your column letter, so try:
srg.AutoFilter sws.Cells(1, sCol).Column, Key

VBA code to copy paste data from multiple source workbooks to a master data workbook (Master data sheet) based on column headers

My code below browses through the folder and effectively picks out the required files but the copy paste codes that I have tried did not work for me. Cant use traditional copy paste as column order is not same. Column names are same though.
Sub ImportExcelfiles()
Dim strPath As String
Dim strFile As String
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim wsTarget As Worksheet
Dim bookName As Worksheet
Dim rowCountSource As Long
Dim colCountSource As Long
Dim rowOutputTarget As Long
Dim colOutputTarget As Long
'Variables for Sheet - Workbook Name
Dim nameCount As Long
Dim fileName As String
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'====================================
'SET THE PATH AND FILE TO THE FOLDER
'====================================
strPath = ThisWorkbook.Worksheets("Control").Range("C4")
fileName = ThisWorkbook.Worksheets("Control").Range("C5")
If Right(strPath, 1) <> "\" Then strPath = strPath & "\"
'set the target worksheet
Set wsTarget = ThisWorkbook.Worksheets("Master Data")
Set bookName = ThisWorkbook.Worksheets("Workbook Name")
'set the initial output row and column count for master data and workbook name
rowOutputTarget = 2
nameCount = 2
'get the first file
strFile = Dir(strPath & "*.xlsx*")
'loop throught the excel files in the folder
Do While strFile <> ""
If InStr(strFile, fileName) > 0 Then
'open the workbook
Set wbSource = Workbooks.Open(strPath & strFile)
Set wsSource = wbSource.Worksheets("Details")
'get the row and column counts
With wsSource
'row count based on column 1 = A
rowCountSource = .Cells(.Rows.Count, 1).End(xlUp).Row
'column count based on row 1
colCountSource = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
-------------------------------Need help here to copy paste-------------------------------------
'copy and paste from A2
wsSource.Range("A3", "AD" & rowCountSource).Copy
wsTarget.Range("A" & rowOutputTarget).PasteSpecial
Paste:=xlPasteValues
bookName.Range("A" & nameCount).Value = wbSource.Name
nameCount = nameCount + 1
rowOutputTarget = rowOutputTarget + rowCountSource - 2
'close the opened workbook
wbSource.Close SaveChanges:=False
End If
'get the next file
strFile = Dir()
Loop
End Sub
Since the order of the columns is different you have to copy them one at a time.
Sub ImportExcelfiles()
Const ROW_COLNAME = 3
'Variables for Sheet - Workbook Name
Dim wbSource As Workbook
Dim wsTarget As Worksheet, wsName As Worksheet
Dim rowOutputTarget As Long, nameCount As Long
Dim strPath As String, strFile As String, fileName As String
With ThisWorkbook
'set the file and path to folder
strPath = .Sheets("Control").Range("C4")
fileName = .Sheets("Control").Range("C5")
If Right(strPath, 1) <> "\" Then strPath = strPath & "\"
'set the target and name worksheets
Set wsTarget = .Sheets("Master Data")
Set wsName = .Sheets("Workbook Name")
End With
' fill dictionary column name to column number from row 1
Dim dict As Object, k As String, rng As Range
Dim lastcol As Long, lastrow As Long, i As Long, n As Long
Set dict = CreateObject("Scripting.Dictionary")
With wsTarget
lastcol = .Cells(1, .Columns.Count).End(xlToLeft).Column
For i = 1 To lastcol
k = UCase(Trim(.Cells(1, i)))
dict.Add k, i
Next
End With
'set the initial output row and column count for master data and workbook nam
rowOutputTarget = 2
nameCount = 2
'get the first file
strFile = Dir(strPath & "*.xlsx*")
'loop through the excel files in the folder
Dim ar, arH, ky, bHasData
Application.ScreenUpdating = False
Do While strFile <> ""
If InStr(strFile, fileName) > 0 Then
'open the workbook
Set wbSource = Workbooks.Open(strPath & strFile, False, False)
wsName.Range("A" & nameCount).Value = wbSource.Name
nameCount = nameCount + 1
' copy values to arrays
With wbSource.Sheets("Details")
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
arH = .Range("A1:AD1").Offset(ROW_COLNAME - 1).Value2 ' col names
ar = .Range("A" & ROW_COLNAME & ":AD" & lastrow).Value2
End With
'close the opened workbook
wbSource.Close SaveChanges:=False
' copy each columns
If lastrow > ROW_COLNAME Then
bHasData = False
For n = 1 To UBound(ar, 2)
k = UCase(Trim(arH(1, n)))
' determine target column using dictonary
' as lookup with approx match
i = 0
For Each ky In dict
If InStr(1, k, ky) > 0 Then
i = dict(ky)
Exit For
End If
Next
' valid match
If i > 0 Then
bHasData = True
Set rng = wsTarget.Cells(rowOutputTarget, i).Resize(UBound(ar))
' copy column n of array to column i of target sheet
rng.Value2 = Application.Index(ar, 0, n)
ElseIf Len(k) > 0 Then
Debug.Print "Column '" & k & "' not found " & strFile
End If
Next
If bHasData Then
rowOutputTarget = rowOutputTarget + UBound(ar) + 2
End If
End If
'get the next file
strFile = Dir()
End If
Loop
Application.ScreenUpdating = True
MsgBox nameCount - 2 & " books", vbInformation
End Sub
Import Data From Files in Folder
Option Explicit
Sub ImportExcelfiles()
' Source
Const sName As String = "Details"
Const siFileExtensionPattern As String = ".xlsx" ' maybe ".xls?" ?
Const sfCol As String = "A"
Const slCol As String = "AD"
Const sfRow As Long = 3
' Destination
Const dName As String = "Master Data"
Const dfCellAddress As String = "A2"
' Destination Lookup
Const dlName As String = "Control"
Const dlsFolderPathAddress As String = "C4"
Const dlsFileNamePatternAddress As String = "C5"
' Destination Name
Const dnName As String = "Workbook Name"
Const dnfCellAddress As String = "A2"
Dim dwb As Workbook: Set dwb = ThisWorkbook
' Destination Lookup Worksheet
' (contains the folder path and the partial file name)
Dim dlws As Worksheet: Set dlws = dwb.Worksheets(dlName)
Dim sFolderPath As String: sFolderPath = dlws.Range(dlsFolderPathAddress)
If Right(sFolderPath, 1) <> "\" Then sFolderPath = sFolderPath & "\"
Dim sFileNamePattern As String ' contains i.e. leading and trailing '*'
sFileNamePattern = "*" & dlws.Range(dlsFileNamePatternAddress) & "*"
Dim sFileExtensionPattern As String
sFileExtensionPattern = siFileExtensionPattern
If Left(sFileExtensionPattern, 1) <> "." Then _
sFileExtensionPattern = "." & sFileExtensionPattern
Dim sFileName As String
sFileName = Dir(sFolderPath & sFileNamePattern & sFileExtensionPattern)
If Len(sFileName) = 0 Then
MsgBox "No files found.", vbCritical ' improve!
Exit Sub
End If
' Destination Worksheet (source data will by copied to)
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
' Source and Destination Columns Count
Dim cCount As Long
cCount = dws.Columns(slCol).Column - dws.Columns(sfCol).Column + 1
' Destination First Row Range
Dim dfrrg As Range: Set dfrrg = dws.Range(dfCellAddress).Resize(, cCount)
' Destination Name Worksheet (source workbook names will be written to)
Dim dnws As Worksheet: Set dnws = dwb.Worksheets(dnName)
' Destination Name Cell
Dim dnCell As Range: Set dnCell = dnws.Range(dnfCellAddress)
Application.ScreenUpdating = False
' Source
Dim swb As Workbook
Dim sws As Worksheet
Dim srg As Range
Dim slRow As Long
' Destination
Dim drg As Range
' Both
Dim rCount As Long
Do While Len(sFileName) > 0
Set swb = Workbooks.Open(sFolderPath & sFileName)
' Attempt to reference the source worksheet.
On Error Resume Next
Set sws = swb.Worksheets("Details")
On Error GoTo 0
If Not sws Is Nothing Then ' worksheet exists
slRow = sws.Cells(sws.Rows.Count, sfCol).End(xlUp).Row
If slRow >= sfRow Then ' found data in column
rCount = slRow - sfRow + 1
Set srg = sws.Cells(sfRow, sfCol).Resize(rCount, cCount)
Set drg = dfrrg.Resize(rCount)
drg.Value = srg.Value
dnCell.Value = swb.Name
' Reset
Set dfrrg = dfrrg.Offset(rCount)
Set dnCell = dnCell.Offset(1)
'Else ' found no data in column; do nothing
End If
Set sws = Nothing
'Else ' worksheet doesn't exist; do nothing
End If
swb.Close SaveChanges:=False
sFileName = Dir
Loop
Application.ScreenUpdating = True
MsgBox "Data imported.", vbInformation
End Sub

Copy rows from multiple workbooks based on cell value

How do I copy cells from a workbook based on a cell-value.
In the excel file that needs to be filled, column B contains a part of a filename in which the data can be found.
B2 contains 312123-145
B3 contains 312123-195
etc,
normally around 18rows, but the loop/step can go until a empty cell if found
The workbook the data contains is the cell-value.xlsm
There is a sheet with name Yield in the 312123-145.xlsm
From that sheet I would like to copy A2:N2, and paste that data at the main excel sheet, in columns E:R in the corrosponding row.
I don't know how to start on to look-up a cell value and find the file with the correct data and then how do I step to the next row.
This the code I started with, I hardcoded first all cellvalues to keep it simple.
Sub ImportWorksheet()
' This macro will import a file into this workbook
Sheets("Sheet1").Select
PathName = "C:\Documents\test\"
Filename = "312123-195"
TabName = "Yield"
ControlFile = ActiveWorkbook.Name
Workbooks.Open Filename:=PathName & Filename
ActiveSheet.Name = TabName
Sheets(TabName).Copy After:=Workbooks(ControlFile).Sheets(1)
Windows(Filename).Activate
ActiveWorkbook.Close SaveChanges:=False
Windows(ControlFile).Activate
End Sub
Import Data From Closed Workbooks
Option Explicit
Sub ImportData()
Dim sFolderPath As String: sFolderPath = "C:\Documents\test\"
Dim sFileExtension As String: sFileExtension = ".xlsm" ' ".xls*"
Const sName As String = "Yield"
Const srgAddress As String = "A2:N2"
Const sFileDelimiter As String = "-"
Const dName As String = "Sheet1"
Const dlCol As String = "B" ' Lookup
Const dvCol As String = "E" ' Value
Const dfRow As Long = 2
If Right(sFolderPath, 1) <> "\" Then sFolderPath = sFolderPath & "\"
If Left(sFileExtension, 1) <> "." Then sFileExtension = "." & sFileExtension
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dlCol).End(xlUp).Row
If dlRow < dfRow Then Exit Sub ' no data
Dim dlrg As Range
Set dlrg = dws.Range(dws.Cells(dfRow, dlCol), dws.Cells(dlRow, dlCol))
Dim dcCount As Long: dcCount = dws.Range(srgAddress).Columns.Count
Dim dvrg As Range: Set dvrg = dws.Cells(dfRow, dvCol).Resize(, dcCount)
Dim swb As Workbook
Dim sws As Worksheet
Dim sFilePattern As String
Dim sFileName As String
Dim dlCell As Range
Dim swsCount As Long
Application.ScreenUpdating = False
For Each dlCell In dlrg.Cells
sFilePattern = sFolderPath & Left(CStr(dlCell.Value), _
InStr(1, CStr(dlCell.Value), sFileDelimiter, vbTextCompare) - 1) _
& sFileExtension
sFileName = Dir(sFilePattern)
If Len(sFileName) > 0 Then ' file (workbook) exists
Set swb = Workbooks.Open(sFolderPath & sFileName)
On Error Resume Next
Set sws = swb.Worksheets(sName)
On Error GoTo 0
If Not sws Is Nothing Then ' worksheet exists
dvrg.Value = sws.Range(srgAddress).Value
swsCount = swsCount + 1
End If
swb.Close SaveChanges:=False
End If
Set dvrg = dvrg.Offset(1)
Next dlCell
Application.ScreenUpdating = True
Select Case swsCount
Case 0
MsgBox "No data imported", vbCritical
Case 1
MsgBox "Data imported from one worksheet.", vbInformation
Case Else
MsgBox "Data imported from " & swsCount & " worksheets.", vbInformation
End Select
End Sub

Append data after last row

My macro is to append the values from three sheets in a weekly report workbook to the values in equivalent sheets in an accumulating workbook.
However, I cannot define the ranges in the ThisWorkbook.Sheets correctly - Only the cell A2 values from the wb.Sheets are appended.
Could someone please help me define the range correctly? Many thanks!
Sub Import_SheetData_ThisWorkbook()
Dim lRow As Long, lRow1 As Long, lRow2 As Long, lRow3 As Long
Dim Path As String, WeeklyCollation As String
Dim wkNum As Integer
Dim wb As Workbook
wkNum = Application.InputBox("Enter week number")
Path = "C:\xyz\"
WeeklyCollation = Path & "Activities 2021 w" & wkNum & ".xlsx"
lRow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row + 1
Set wb = Workbooks.Open(WeeklyCollation)
lRow1 = wb.Sheets("Customer visits").Cells(Rows.Count, 1).End(xlUp).Row
lRow2 = wb.Sheets("Orders").Cells(Rows.Count, 1).End(xlUp).Row
lRow3 = wb.Sheets("Visits").Cells(Rows.Count, 1).End(xlUp).Row
'Replace with copy and paste
'Can't define range in ThisWorkbook
ThisWorkbook.Sheets("Customer visits").Range("A" & lRow + 1).Value = wb.Sheets("Customer visits").Range("A2:H" & lRow1).Value
ThisWorkbook.Sheets("Orders").Range("A" & lRow + 1).Value = wb.Sheets("Orders").Range("A2:I" & lRow2).Value
ThisWorkbook.Sheets("Visits").Range("A" & lRow + 1).Value = wb.Sheets("Visits").Range("A2:F" & lRow3).Value
wb.Close SaveChanges:=False
MsgBox ("Data added")
End Sub
Backup Data
Adjust the values in the constants section.
Option Explicit
Sub ImportSheetData()
' Constants
' Source
Const sPath As String = "C:\xyz\"
Const swsNamesList As String = "Customer visits,Orders,Visits"
Const slrCol As String = "A"
Const sfRow As Long = 2
' Destination
Const dwsNamesList As String = "Customer visits,Orders,Visits"
Const dlrCol As String = "A"
' Both
Const Cols As String = "A:H"
' Create the references to the workbooks.
Dim wkNum As Variant: wkNum = Application.InputBox( _
"Enter week number", "Import Sheet Data", , , , , , 1)
If wkNum = False Then
MsgBox "You canceled.", vbExclamation
Exit Sub
End If
Dim sWeeklyCollation As String
sWeeklyCollation = sPath & "Activities 2021 w" & wkNum & ".xlsx"
Dim swb As Workbook
On Error Resume Next
Set swb = Workbooks.Open(sWeeklyCollation)
On Error GoTo 0
If swb Is Nothing Then
MsgBox "Could not find the file '" & sWeeklyCollation & "'.", vbCritical
Exit Sub
End If
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
' Copy the data.
Dim swsNames() As String: swsNames = Split(swsNamesList, ",")
Dim dwsNames() As String: dwsNames = Split(dwsNamesList, ",")
Dim sws As Worksheet
Dim srg As Range
Dim slRow As Long
Dim dws As Worksheet
Dim drg As Range
Dim dCell As Range
Dim n As Long
Dim rCount As Long
Dim wsCount As Long ' Counts the number of worksheets processed
For n = 0 To UBound(swsNames)
On Error Resume Next
Set sws = swb.Worksheets(swsNames(n))
On Error GoTo 0
If Not sws Is Nothing Then ' source worksheet exists
On Error Resume Next
Set dws = dwb.Worksheets(dwsNames(n))
On Error GoTo 0
If Not dws Is Nothing Then ' destination worksheet exists
slRow = sws.Cells(sws.Rows.Count, slrCol).End(xlUp).Row
rCount = slRow - sfRow + 1
If rCount > 0 Then ' found data in source worksheet
Set srg = sws.Columns(Cols).Resize(rCount).Offset(sfRow - 1)
Set dCell = dws.Cells(dws.Rows.Count, dlrCol) _
.End(xlUp).Offset(1)
Set drg = dCell.Resize(rCount).EntireRow.Columns(Cols)
drg.Value = srg.Value
wsCount = wsCount + 1
' Else ' no data in source worksheet
End If
'Else ' destination worksheet doesn't exist
End If
'Else ' source worksheet doesn't exist
End If
Next n
' Finishing Touches
swb.Close SaveChanges:=False
'dwb.Save
' Or:
'dwb.Close SaveChanges:=True
MsgBox "Data from " & wsCount & " worksheets added.", vbInformation
End Sub

EXCEL-VBA How to export to a CSV... a custom range of columns?

I have the following VBA macro that I get from the web, a long time ago... and it´s working OK in Excel:
Sub ExportCSV()
Dim MyFileName As String
Dim CurrentWB As Workbook, TempWB As Workbook
Set CurrentWB = ActiveWorkbook
ActiveWorkbook.ActiveSheet.UsedRange.Copy
Set TempWB = Application.Workbooks.Add(1)
With TempWB.Sheets(1).Range("A1")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
MyFileName = CurrentWB.Path & "\FOLDER\" & Left(CurrentWB.Name, InStrRev(CurrentWB.Name, ".") - 1) & ".csv"
'Optionally, comment previous line and uncomment next one to save as the current sheet name
'MyFileName = CurrentWB.Path & "\" & CurrentWB.ActiveSheet.Name & ".csv"
Application.DisplayAlerts = False
TempWB.SaveAs Filename:=MyFileName, FileFormat:=xlCSVUTF8, CreateBackup:=False, Local:=False
TempWB.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub
I just need to edit/modify it to get only columns in the range "A:AV", to reduce the CSV file size... and simply, don´t know how to do it!
Can anyone help me?
Export Columns to CSV
Adjust the values in the constants section.
If your list separator is a semicolon, you may want to use Local:=True.
Option Explicit
Sub ExportColumnsToCSV()
Const sfRow As Long = 1
Const sColsList As String = "A:F,H:I,V,AM:AV"
Const dFirst As String = "A1"
Dim sCols() As String: sCols = Split(sColsList, ",")
Dim sws As Worksheet: Set sws = ActiveSheet
Dim swb As Workbook: Set swb = sws.Parent
Dim srrg As Range
Dim slCell As Range
Dim srCount As Long
With sws.Rows(sfRow)
Set slCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If slCell Is Nothing Then
MsgBox "No data in worksheet.", vbCritical, "Export to CSV"
Exit Sub
End If
srCount = slCell.Row - .Row + 1
Set srrg = .Resize(srCount)
End With
Dim srg As Range
Dim n As Long
For n = 0 To UBound(sCols)
If srg Is Nothing Then
Set srg = Intersect(srrg, sws.Columns(sCols(n)))
Else
Set srg = Union(srg, Intersect(srrg, sws.Columns(sCols(n))))
End If
Next n
Dim dwb As Workbook: Set dwb = Application.Workbooks.Add
srg.Copy
dwb.Worksheets(1).Range(dFirst).PasteSpecial xlPasteValues
Dim dFolderPath As String: dFolderPath = swb.Path & "\Folder\"
On Error Resume Next
MkDir dFolderPath
On Error GoTo 0
Dim dFilePath As String
dFilePath = dFolderPath _
& Left(swb.Name, InStrRev(swb.Name, ".") - 1) & ".csv"
' Optionally, out-comment previous line and uncomment next one
' to save with the current worksheet name.
'dFilePath = dFolderPath & sws.Name & ".csv"
Application.DisplayAlerts = False
dwb.SaveAs Filename:=dFilePath, FileFormat:=xlCSVUTF8, Local:=False
dwb.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub
Just for the sake of using arrays, next code will not use the clipboard. It is fast even for big ranges to be processed:
Sub ExportColumnsToCSV_Array()
Const sfRow As Long = 1
Const sColsList As String = "A:F,H:I,V,AM:AV"
Const dFirst As String = "A1"
Dim sCols() As String: sCols = Split(sColsList, ",")
Dim sws As Worksheet: Set sws = ActiveSheet
Dim swb As Workbook: Set swb = sws.Parent
Dim srrg As Range
Dim slCell As Range, arrCol, arr, lastRow As Long, lastCol As Long
If sws.UsedRange.cells.count <= 1 Then Exit Sub 'to avoid the next checking of lastRow and lastCol
With sws.rows(sfRow)
lastRow = .Resize(.Worksheet.rows.count - sfRow + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious).row 'last row of the range to be copied
End With
lastCol = ActiveSheet.Range("A1").SpecialCells(xlCellTypeLastCell).Column 'and its last column
arr = sws.Range("A1").Resize(lastRow, lastCol).value 'places the range to be copied in an array
'obtain array of necessary columns numbers:
arrCol = buildColAr(sColsList)
Debug.Print Join(arrCol, ","): 'just to see what array has been returned...
'Extract from the initial array only the necessary columns:
arr = Application.Index(arr, Application.Evaluate("row(1:" & lastRow & ")"), arrCol)
Dim dwb As Workbook: Set dwb = Application.Workbooks.Add
'drop the processed array result, at once:
dwb.Worksheets(1).Range(dFirst).Resize(UBound(arr), UBound(arr, 2)).value = arr
Dim dFolderPath As String: dFolderPath = swb.Path & "\Folder\"
If Dir(dFolderPath, vbDirectory) = "" Then MkDir dFolderPath
Dim dFilePath As String
dFilePath = dFolderPath & left(swb.Name, InStrRev(swb.Name, ".") - 1) & ".csv"
Application.DisplayAlerts = False
dwb.saveas FileName:=dFilePath, FileFormat:=xlCSVUTF8, Local:=False
dwb.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub
Private Function buildColAr(ByVal v As Variant) As Variant
Dim i&, temp, cols As Long, arrFilt, El, j As Long, k As Long
v = Split(v, ","): arrFilt = Filter(v, ":", True) 'in arrFilt will be kept the continuous ranges (like A:F)
For Each El In arrFilt
cols = cols + Range(El).Columns.count 'calculate the total number of columns to ReDim the array able to keep them
Next
ReDim temp(LBound(v) To UBound(v) - UBound(arrFilt) + cols - 1) 'Redim the necessary array to keep the columns number
For i = LBound(v) To UBound(v)
If InStr(v(i), ":") > 0 Then 'the case of adiacent columns ranges
For j = 1 To Range(v(i)).Columns.count
temp(k) = Range(v(i)).Columns(j).Column: k = k + 1
Next j
Else
temp(k) = cells(1, v(i)).Column: k = k + 1
End If
Next i
buildColAr = temp
End Function

Resources