Change existing macro to copy formulas from specific columns - vba

This is my still my first macro, I have been searching like a mad man trying to get this to work...and it's getting close!
I have it set to copy "Pricing_Cost" sheet from Active workbook into a new workbook as values and then manipulate it beyond that. What I really need is to modify that step so that certain columns copy values, others copy formulas. I have columns A:X
Columns needing to be pasted as values = A,E,F,H,I,J,K,L,M,N,T,U,V,W,X
Columns needing to pasted as formula = B,C,D,G,O,P,Q,R,S
This is within the CopyRemoveFormSave sub
I'm guessing maybe I should copy the whole thing as formulas and then cut and paste as values the columns that need to be converted to values? Not really sure how to do that with the code I have here...
Public strFile As String
Sub RunAll()
Call load_csv
Call CopyRemoveFormAndSave
Call Splitbook
End Sub
Sub load_csv()
Dim fStr As String
With Application.FileDialog(msoFileDialogFilePicker)
.Show
If .SelectedItems.Count = 0 Then
MsgBox "Cancel Selected"
Exit Sub
End If
'fStr is the file path and name of the file you selected.
fStr = .SelectedItems(1)
End With
Sheets("Product_Weekly").UsedRange.ClearContents
With ThisWorkbook.Sheets("Product_Weekly").QueryTables.Add(Connection:= _
"TEXT;" & fStr, Destination:=ThisWorkbook.Sheets("Product_Weekly").Range("$A$1"))
.Name = "CAPTURE"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
Declare PtrSafe Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _
(ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Const MAX_PATH As Long = 260
'~~> Function to get user's temp directoy
Function TempPath() As String
TempPath = String$(MAX_PATH, Chr$(0))
GetTempPath MAX_PATH, TempPath
TempPath = Replace(TempPath, Chr$(0), "")
End Function
Sub CopyRemoveFormAndSave()
Dim wb As Workbook, wbNew As Workbook
Dim ws As Worksheet
Dim wsName As String, NewName As String
' Dim shp As Shape
Set wb = ThisWorkbook
wsName = ActiveSheet.Name
NewName = wsName & ".xlsm"
wb.SaveCopyAs TempPath & NewName
Set wbNew = Workbooks.Open(TempPath & NewName)
wbNew.Sheets(wsName).UsedRange.Value = wbNew.Sheets(wsName).UsedRange.Value
Application.DisplayAlerts = False
For Each ws In wbNew.Worksheets
If ws.Name <> wsName Then ws.Delete
Next ws
Application.DisplayAlerts = True
' For Each shp In wbNew.Sheets(wsName).Shapes
' If shp.Type = 8 Then shp.Delete
' Next
'
'~~> Do a save as for the new workbook if required.
'
'End Sub
Columns("W:W").Replace "2", "KevinClark", xlWhole
Columns("W:W").Replace "9", "PaulG", xlWhole
Columns("W:W").Replace "O", "KevinClark", xlWhole
Columns("W:W").Replace "I", "KevinClark", xlWhole
Columns("W:W").Replace "4", "PaulG", xlWhole
Columns("W:W").Replace "8", "KevinClark", xlWhole
Columns("W:W").Replace "7", "KevinClark", xlWhole
'Sub SplitData()
Const NameCol = "W"
Const HeaderRow = 3
Const FirstRow = 4
Dim SrcSheet As Worksheet
Dim TrgSheet As Worksheet
Dim SrcRow As Long
Dim LastRow As Long
Dim TrgRow As Long
Dim Buyer As String
Application.ScreenUpdating = False
Set SrcSheet = ActiveSheet
LastRow = SrcSheet.Cells(SrcSheet.Rows.Count, NameCol).End(xlUp).Row
For SrcRow = FirstRow To LastRow
Buyer = SrcSheet.Cells(SrcRow, NameCol).Value
Set TrgSheet = Nothing
On Error Resume Next
Set TrgSheet = Worksheets(Buyer)
On Error GoTo 0
If TrgSheet Is Nothing Then
Set TrgSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
TrgSheet.Name = Buyer
' SrcSheet.Range(HeaderRow).Copy Destination:=TrgSheet.Range(HeaderRow)
SrcSheet.Range("A1:W3").Copy Destination:=TrgSheet.Range("A1:W3")
End If
TrgRow = TrgSheet.Cells(TrgSheet.Rows.Count, NameCol).End(xlUp).Row + 1
SrcSheet.Rows(SrcRow).Copy Destination:=TrgSheet.Rows(TrgRow)
Next SrcRow
Application.ScreenUpdating = True
Dim sht As Worksheet
''AutoFit One Column
' ThisWorkbook.Worksheets("Sheet1").Columns("O:O").EntireColumn.AutoFit
'
''AutoFit Multiple Columns
' ThisWorkbook.Worksheets("Sheet1").Range("I:I,L:L").EntireColumn.AutoFit 'Columns I & L
' ThisWorkbook.Worksheets("Sheet1").Range("I:L").EntireColumn.AutoFit 'Columns I to L
'
''AutoFit All Columns on Worksheet
' ThisWorkbook.Worksheets("Sheet1").Cells.EntireColumn.AutoFit
'AutoFit Every Worksheet Column in a Workbook
For Each sht In wbNew.Worksheets
sht.Cells.EntireColumn.AutoFit
Next sht
End Sub
Sub Splitbook()
'Updateby20140612
Dim xPath As String
xPath = "C:\Users\Jimbo.JAMESP-ACERLT\Documents\For Gary\Output"
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Each xWs In ActiveWorkbook.Sheets
If xWs.Name <> "Pricing Cost" Then
xWs.Copy
Application.ActiveWorkbook.SaveAs Filename:=xPath & "\" & xWs.Name & ".xlsx"
Application.ActiveWorkbook.Close False
End If
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

As you say I think the best step is to copy all as formulas initially. What I would do next is define an array which contains the column letters which you need to be values, you can do that as follows.
ValArr = Array("A","E","F","H","I","J","K","L","M","N","T","U","V","W","X")
Then you can loop through this array and turn each column to values.
For x = Lbound(ValArr) To Ubound(ValArr)
'Paste values in column ValArr(x)
Next
I hope this helps, let me know if you need any more clarification.

You can do it without any copy and pasting. For example let's say you want to copy all the formulas from Sheet1 to Sheet2 you can do something like this:
for i = 1 to lastRow
for j in 1 to lastCol
Sheets("Sheet2").cells(i,j).formula = Sheets("Sheet1").cells(i,j).formula
next j
next i
Also if there's no formula it just copies the text so you can do that for all the cells.

Related

Loop through Folder of Excel Workbooks and Append only Workbooks with a Key Word to Master Sheet

I am looking for VBA code that would look through several hundred Workbooks and open only ones that have "cash" in the workbook title. It would then pull the second row of the first worksheet down to the last row and append it to a master worksheet.
Although I see the iteration count reaches all one hundred plus workbooks, the code appends only the first few worksheets and stops. Could anyone provide insight as to why that is happening? Thank you in advance!
Sub Pull_Cash_WB_Names()
Dim filename As Variant
Dim a As Integer
a = 1
Dim wbDst As Workbook
Dim wbSrc As Workbook
Dim wsSrc As Worksheet
Dim MyPath As String
Dim strFilename As String
Dim LRow As Long, LCol As Long
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayStatusBar = True
Set wbDst = ThisWorkbook
strFilename = Dir("\\DATA\*Cash*")
Count = 0
Do While strFilename <> ""
Set wbSrc = Workbooks.Open("\\DATA\*Cash*")
Set wsSrc = wbSrc.Worksheets(1)
'copy all cells starting from 2nd row to last column
LRow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
LCol = ActiveSheet.Cells(7, Columns.Count).End(xlToLeft).Column
Cells(2, 1).Resize(LRow - 1, LCol).Select
Selection.Copy
'paste the data into master file
wbDst.Sheets(wbDst.Worksheets.Count).Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
'counts the number of iterations
Count = Count + 1
Application.StatusBar = Count
wbSrc.Close False
strFilename = Dir()
Loop
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
See fixes/suggestions below
Sub Pull_Cash_WB_Names()
Const PTH As string = "\\DATA\" 'folder path goes here
Dim wbDst As Workbook
Dim wbSrc As Workbook
Dim strFilename As String
Dim rngCopy AsRange, rngDest as range
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayStatusBar = True
Set wbDst = ThisWorkbook
Set rngDest = wbDst.Sheets(wbDst.Worksheets.Count).Range("A1") 'start pasting here
strFilename = Dir(PTH & "*Daily*Cash*.csv") '#EDIT#
Count = 0
Do While strFilename <> ""
Set wbSrc = Workbooks.Open(PTH & strFilename) 'full path+name
Set rngCopy = wbSrc.Worksheets(1).Range("A1").CurrentRegion 'whole table
Set rngCopy = rngCopy.Offset(1, 0).resize(rngcopy.rows.count-1) 'exclude headers
rngCopy.Copy
'paste the data into master file
rngDest.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Set rngDest = rngDest.offset(rngCopy.rows.count) 'next paste goes here...
Count = Count + 1
Application.StatusBar = Count
wbSrc.Close False
strFilename = Dir()
Loop
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub

Import multiple text files into single worksheet

I found the following code which imports each text file into a separate worksheet and it worked perfectly. Is there a way to modify the code so ALL text files are imported into a SINGLE worksheet?
I'm using Excel 2013 on Windows7 64 bit if that makes a difference.
Sub ImportTXTFiles()
Dim fso As Object
Dim xlsheet As Worksheet
Dim qt As QueryTable
Dim txtfilesToOpen As Variant, txtfile As Variant
Application.ScreenUpdating = False
Set fso = CreateObject("Scripting.FileSystemObject")
txtfilesToOpen = Application.GetOpenFilename _
(FileFilter:="Text Files (*.txt), *.txt", _
MultiSelect:=True, Title:="Text Files to Open")
For Each txtfile In txtfilesToOpen
' FINDS EXISTING WORKSHEET
For Each xlsheet In ThisWorkbook.Worksheets
If xlsheet.Name = Replace(fso.GetFileName(txtfile), ".txt", "") Then
xlsheet.Activate
GoTo ImportData
End If
Next xlsheet
' CREATES NEW WORKSHEET IF NOT FOUND
Set xlsheet = ThisWorkbook.Worksheets.Add( _
After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
xlsheet.Name = Replace(fso.GetFileName(txtfile), ".txt", "")
xlsheet.Activate
GoTo ImportData
ImportData:
' DELETE EXISTING DATA
ActiveSheet.Range("A:Z").EntireColumn.Delete xlShiftToLeft
' IMPORT DATA FROM TEXT FILE
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & txtfile, _
Destination:=ActiveSheet.Cells(1, 1))
.TextFileParseType = xlDelimited
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.Refresh BackgroundQuery:=False
End With
For Each qt In ActiveSheet.QueryTables
qt.Delete
Next qt
Next txtfile
Application.ScreenUpdating = True
MsgBox "Successfully imported text files!", vbInformation, "SUCCESSFUL IMPORT"
Set fso = Nothing
End Sub
A lot of the code in here is dealing with creating new tabs etc. so that can go.
What you're left with is a loop that loads each text file into Cells(1,1) - so if we tweak that to point at a value which checks the last used cell in column A, then this should do what you need:
Sub ImportTXTFiles()
Dim fso As Object
Dim xlsheet As Worksheet
Dim qt As QueryTable
Dim txtfilesToOpen As Variant, txtfile As Variant
Application.ScreenUpdating = False
Set fso = CreateObject("Scripting.FileSystemObject")
txtfilesToOpen = Application.GetOpenFilename _
(FileFilter:="Text Files (*.txt), *.txt", _
MultiSelect:=True, Title:="Text Files to Open")
With ActiveSheet
For Each txtfile In txtfilesToOpen
importrow = 1 + .Cells(.Rows.Count, 1).End(xlUp).Row
' IMPORT DATA FROM TEXT FILE
With .QueryTables.Add(Connection:="TEXT;" & txtfile, _
Destination:=.Cells(importrow, 1))
.TextFileParseType = xlDelimited
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.Refresh BackgroundQuery:=False
End With
Next txtfile
For Each qt In .QueryTables
qt.Delete
Next qt
End With
Application.ScreenUpdating = True
MsgBox "Successfully imported text files!", vbInformation, "SUCCESSFUL IMPORT"
Set fso = Nothing
End Sub
Also, I notice you delete 'all' the query tables inside your loop. This isn't necessary. Just delete them all once they're all loaded.
I believe the following will do what you expect, this will bring all your text data into a single worksheet, it will check for the last row with data in Column A, and offset by one row to import data from the next Text File:
Sub ImportTXTFiles()
Dim fso As Object
Dim xlsheet As Worksheet
Dim qt As QueryTable
Dim LastRow As Long
Dim txtfilesToOpen As Variant, txtfile As Variant
Application.ScreenUpdating = False
Set fso = CreateObject("Scripting.FileSystemObject")
txtfilesToOpen = Application.GetOpenFilename _
(FileFilter:="Text Files (*.txt), *.txt", _
MultiSelect:=True, Title:="Text Files to Open")
For Each txtfile In txtfilesToOpen
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
' IMPORT DATA FROM TEXT FILE
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & txtfile, _
Destination:=ActiveSheet.Cells(LastRow, 1))
.TextFileParseType = xlDelimited
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.Refresh BackgroundQuery:=False
End With
For Each qt In ActiveSheet.QueryTables
qt.Delete
Next qt
Next txtfile
Application.ScreenUpdating = True
MsgBox "Successfully imported text files!", vbInformation, "SUCCESSFUL IMPORT"
Set fso = Nothing
End Sub

Pick folder routine going to Error handler - Excel VBA

Below is code that allows the user to choose a folder and opens files within the folder. It essentially does this:
On open, look for filepath saved in worksheet in workbook based on username. If doesn't exist, then prompt user to find folder, then save filepath in worksheet
From step 1, if filepath is found based on user, use that filepath
Error handler: From step 1, if filepath is found based on user, but that filepath is not in use anymore(i.e. user moved the folder to a different filepath), then have user find the folder again, then update existing record
What i'm experiencing is this:
When there's no entries in the sheet, then it will prompt user to
find the folder, but then proceed to the errorhandler and ask the
user to find the folder again
When there are entries in the sheet and the file path is working, the errorhandler is still opened and asks the user to find the
folder again
If I take out the errorhandler, everything is smooth. It's just that I want to cover the possibility of the user moving the folder , so I want the workbook to prompt the user to find where they moved the folder, and update the existing record in the workbook to the new path
What am I doing wrong here?
Private Sub Workbook_Open()
Dim wkb1 As Workbook
Dim sht1 As Worksheet
Dim wkb2 As Workbook
Dim sht2 As Worksheet
Dim vafiles As Variant
Dim filepath As String
Dim filepath2 As String
Dim filepath3 As String
Dim rw As Long
Dim ws As Worksheet
Dim lastrow As Long
Dim icounter As Long
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.Calculation = xlManual
Set ws = Worksheets("Paths")
rw = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
Set wkb1 = ThisWorkbook
Set sht1 = wkb1.Sheets("Extract")
'======================================================
'Determine if Path was already saved before. If not, prompt user to choose folder
'======================================================
sal = Application.VLookup(Environ("username"), ws.Range("a:b"), 2, 0)
If IsError(sal) Then
MsgBox ("Please choose where your main folder is located. This will be stored so you won't need to look for it again.")
filepath = PICK_A_FOLDER()
ws.Cells(rw, 2) = PICK_A_FOLDER()
ws.Cells(rw, 1) = Environ("username")
Set wkb2 = Workbooks.Open(filepath & "\ Export.xlsx")
Set sht2 = wkb2.Sheets("Sheet1")
sht2.Cells.Copy Destination:=sht1.Range("a1")
Application.CutCopyMode = False
wkb2.Close True
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
Worksheets("Instructions").Activate
Application.Calculation = xlAutomatic
Else
'======================================================
'If filepath exists, use that one
'======================================================
filepath2 = sal
Set wkb2 = Workbooks.Open(filepath2 & "Export.xlsx")
Set sht2 = wkb2.Sheets("Sheet1")
sht2.Cells.Copy Destination:=sht1.Range("a1")
Application.CutCopyMode = False
wkb2.Close True
End If
'======================================================
'If user has moved their folder, we can find it again and update their record
'======================================================
On Error GoTo Errorhandler
Errorhandler:
MsgBox ("Looks like you've moved your Folder. Please find it so your record will be updated")
filepath3 = PICK_A_FOLDER()
lastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
For icounter = 2 To lastrow
If Cells(icounter, 1) = Environ("username") Then
Cells(icounter, 2) = PICK_A_FOLDER()
End If
Next icounter
Set wkb2 = Workbooks.Open(filepath3 & "")
Set sht2 = wkb2.Sheets("Sheet1")
sht2.Cells.Copy Destination:=sht1.Range("a1")
Application.CutCopyMode = False
wkb2.Close True
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
Worksheets("Instructions").Activate
Application.Calculation = xlAutomatic
End Sub
Actually solved this by taking out the errorhandler and inserting another if statement that captures an invalid directory:
if dir(sal & "Export.xlsx") = "" then
write error handler code
When a SubRoutine performs more that one task you should consider extracting the individual tasks into separate SubRoutines.
In this way:
You can debug each task independently of the other tasks
The logic is simplified into smaller units
The code is easier to read
You can reduce clutter by placing these SubRoutines into separate modules
Possible code reuse
Another unapparent benefit is that by simplifying the function of a SubRoutine it is much easier to remember the routines pattern and reuse the pattern when a similar situation arises.
Note: I often use If Len(...) then which is analogous to If Len(...) > 0 then. I do this to reduce clutter.
Standard Module
Function getSharedFolder() As String
Dim f As Range
With Worksheets("Paths")
Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Find(What:=Environ("username"), After:=.Range("A1"), LookAt:=xlWhole)
If Not f Is Nothing Then
'Dir([PathName], vbDirectory) returns empty if the [PathName] isn't a folder
If Len(Dir(f.Offset(0, 1).Value, vbDirectory)) Then
If Right(f.Offset(0, 1), 1) = "\" Then
getSharedFolder = f.Offset(0, 1)
Else
getSharedFolder = f.Offset(0, 1) & "\"
End If
End If
End If
End With
End Function
Function setSharedFolder() As Boolean
Dim f As Range
Dim PathName As String
PathName = PickSharedFolder
If Len(PathName) Then
setSharedFolder = True
With Worksheets("Paths")
Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Find(What:=Environ("username"), After:=.Range("A1"), LookAt:=xlWhole)
If f Is Nothing Then Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Offset(1)
f.Value = Environ("username")
f.Offset(0, 1) = PathName
End With
End If
End Function
Function PickSharedFolder() As String
Application.FileDialog(msoFileDialogFolderPicker).ButtonName = "Select Folder"
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Title = "Select Main Folder Location"
If .Show = -1 And .SelectedItems.Count = 1 Then
PickSharedFolder = .SelectedItems(1)
Else: Exit Function
End If
End With
End Function
Sub ToggleEvents(EnableEvents As Boolean, Optional DisplayAlerts = True)
With Application
.DisplayAlerts = DisplayAlerts
.EnableEvents = EnableEvents
.ScreenUpdating = EnableEvents
.Calculation = IIf(EnableEvents, xlCalculationAutomatic, xlCalculationManual)
End With
End Sub
Sub UpdateWorkBook(FilePath As String)
Dim WSSource As Worksheet
With Workbooks.Open(FilePath)
Set WSSource = .Sheets("Sheet1")
If WSSource Is Nothing Then
MsgBox "Sheet1 not found in " & FILENAME, vbCritical, "Update Cancelled"
Else
WSSource.Copy Destination:=ThisWorkbook.Sheets("Extract").Range("A1")
End If
.Close True
End With
End Sub
Workbook Module
Private Sub Workbook_Open()
Const FILENAME As String = "Export.xlsx"
Const PROMPT As String = "Press [Yes] to continue or [No] to cancel"
Dim FilePath As String, Title As String, SharedFolder As String
ToggleEvents False, False
Do
SharedFolder = getSharedFolder()
If Len(SharedFolder) = 0 Then
Title = "Folder not found"
Else
FilePath = SharedFolder & FILENAME
If Len(Dir(FilePath)) = 0 Then Title = "File not found"
End If
If Len(SharedFolder) = 0 Then
If MsgBox(PROMPT:=PROMPT, Buttons:=vbYesNo, Title:=Title) = vbYes Then
setSharedFolder
Else
Exit Sub
End If
End If
Loop Until Len(Dir(FilePath))
UpdateWorkBook FilePath
ToggleEvents True, True
End Sub

Import multiple text/csv files into single excel worksheet

I found this code to get the data from multiple csv/text files into an excel workbook. However, I would like the data to be appended to a single worksheet rather than each csv/text file having its own worksheet.
I have tried using Connection to get the data but when the file is being emailed to another user, there is an error prompt (Excel cannot find the text file to refresh this external data range) when he/she clicks on "Enable Content".
Sub CombineTextFiles()
Dim FilesToOpen
Dim x As Integer
Dim wkbAll As Workbook
Dim wkbTemp As Workbook
Dim sDelimiter As String
On Error GoTo ErrHandler
Application.ScreenUpdating = False
sDelimiter = "|"
FilesToOpen = Application.GetOpenFilename _
(FileFilter:="CSV Files (*.csv), *.csv", _
MultiSelect:=True, Title:="Text Files to Open")
If TypeName(FilesToOpen) = "Boolean" Then
MsgBox "No Files were selected"
GoTo ExitHandler
End If
x = 1
Set wkbTemp = Workbooks.Open(Filename:=FilesToOpen(x))
wkbTemp.Sheets(1).Copy
Set wkbAll = ActiveWorkbook
wkbTemp.Close (False)
wkbAll.Worksheets(x).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:="|"
x = x + 1
While x <= UBound(FilesToOpen)
Set wkbTemp = Workbooks.Open(Filename:=FilesToOpen(x))
With wkbAll
wkbTemp.Sheets(1).Move After:=.Sheets(.Sheets.Count)
.Worksheets(x).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:=sDelimiter
End With
x = x + 1
Wend
ExitHandler:
Application.ScreenUpdating = True
Set wkbAll = Nothing
Set wkbTemp = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description
Resume ExitHandler
End Sub
Consider using QueryTables that connect to your text files and wrap in a loop of your multiple selected csv files from the array, filesToOpen:
Sub ImportCSVFiles()
Dim filesToOpen As Variant, file As Variant, LastRow As Long, fso As Object
filesToOpen = Application.GetOpenFilename _
(FileFilter:="CSV Files (*.csv), *.csv", _
MultiSelect:=True, Title:="Text Files to Open")
For Each file In filesToOpen
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
Set fso = CreateObject("Scripting.FileSystemObject")
fileName = fso.GetFilename(i)
If file = "False" Then Exit Sub
'IMPORT DATA FROM CSV FILES
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & file, _
Destination:=Cells(LastRow + 2, 1))
.TextFileStartRow = 30
.TextFileParseType = xlDelimited
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.Refresh BackgroundQuery:=False
End With
Next file
' REMOVING SOURCE CONNECTIONS
For Each qt In ActiveSheet.QueryTables
qt.Delete
Next qt
End Sub
I used this one to get the files. The downside is it gets to pull all data into this workbook.
Sub getallbooks()
Dim firstRowHeaders As Boolean
Dim fso As Object
Dim dir As Object
Dim filename As Variant
Dim wb As Workbook
Dim s As Sheet1
Dim thisSheet As Sheet1
Dim lastUsedRow As Range
Dim file As String
Dim fpath As String
On Error GoTo ErrMsg
Application.ScreenUpdating = False
firstRowHeaders = True 'Change from True to False if there are no headers in the first row
Set fso = CreateObject("Scripting.FileSystemObject")
'PLEASE NOTE: Change <<Full path to your Excel files folder>> to the path to the folder containing your Excel files to merge
fpath = Application.InputBox("Enter the file folder")
Set dir = fso.Getfolder(fpath)
Set thisSheet = ThisWorkbook.ActiveSheet
For Each filename In dir.Files
'Open the spreadsheet in ReadOnly mode
Set wb = Application.Workbooks.Open(filename, ReadOnly:=True)
'Copy the used range (i.e. cells with data) from the opened spreadsheet
If firstRowHeaders And i > 0 Then 'Only include headers from the first spreadsheet
Dim mr As Integer
mr = wb.ActiveSheet.UsedRange.Rows.Count
wb.ActiveSheet.UsedRange.Offset(1, 0).Resize(mr - 1).Copy
Else
wb.ActiveSheet.UsedRange.Copy
End If
'Paste after the last used cell in the master spreadsheet
If Application.Version < "12.0" Then 'Excel 2007 introduced more rows
Set lastUsedRow = thisSheet.Range("A65536").End(xlUp)
Else
Set lastUsedRow = thisSheet.Range("A1048576").End(xlUp)
End If
'Only offset by 1 if there are current rows with data in them
If thisSheet.UsedRange.Rows.Count > 1 Or Application.CountA(thisSheet.Rows(1)) Then
Set lastUsedRow = lastUsedRow.Offset(1, 0)
End If
lastUsedRow.PasteSpecial
Application.CutCopyMode = False
Next filename
ThisWorkbook.Save
Set wb = Nothing
#If Mac Then
'Do nothing. Closing workbooks fails on Mac for some reason
#Else
'Close the workbooks except this one
For Each filename In dir.Files
file = Right(filename, Len(filename) - InStrRev(filename, Application.PathSeparator, , 1))
Workbooks(file).Close SaveChanges:=False
Next filename
#End If
Application.ScreenUpdating = True
ErrMsg:
If Err.Number <> 0 Then
MsgBox "There was an error. Please try again. [" & Err.Description & "]"
End If
End Sub
Here is another way which creates a new workbook to store the data:
Sub MergeAllWorkbooks()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim LastRow As Long, LastCol As Long
' Change this to the path\folder location of your files.
MyPath = InputBox("Enter the address here")
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.csv*") 'You can change the file type to suit your need here
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Set various application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
' Add a new workbook with one sheet.
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
' Loop through all files in the myFiles array.
If FNum > 0 Then
For FNum = LBound(MyFiles) To UBound(MyFiles)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(MyPath & MyFiles(FNum))
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
' Change this range to fit your own needs.
With mybook.Worksheets(1)
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row 'choose which column has data all the way down the last row
LastCol = .Cells(1, Columns.Count).End(xlToLeft).Column
Set sourceRange = .Range(.Cells(1, 1), .Cells(LastRow, LastCol))
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If source range uses all columns then
' skip this file.
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A, if you want; Here I choose not.
' With sourceRange
' BaseWks.Cells(rnum, "A"). _
' Resize(.Rows.Count).Value = MyFiles(FNum)
' End With
' Set the destination range.
Set destrange = BaseWks.Range("A" & rnum)
' Copy the values from the source range
' to the destination range.
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Both of them get the header from each files. So You may want to remove them with only the top one left alone.
Thanks for the replies. Instead of using the code that i have shared above, I re-used connection which was my original code. To counter the connection error prompt (Excel cannot find the text file to refresh this external data range) when he/she clicks on "Enable Content", I added a code which removes all connections after the data is imported into the excel file. Hope this is helpful to someone who encountered the same issue as me. :)
Sub ImportMultipleCSV()
Dim myfiles
Dim i As Integer
myfiles = Application.GetOpenFilename(filefilter:="CSV Files (*.csv), *.csv", MultiSelect:=True)
If IsArray(myfiles) Then
For i = LBound(myfiles) To UBound(myfiles)
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;" & myfiles(i), Destination:=Range("A" & Rows.Count).End(xlUp).Offset(1, 0))
.Name = "Sample"
.FieldNames = False
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 2
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = True
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
Next i
Else
MsgBox "No File Selected"
End If
Dim xConnect As Object
For Each xConnect In ActiveWorkbook.Connections
If xConnect.Name <> "ThisWorkbookDataModel" Then xConnect.Delete
Next xConnect
End Sub

Creating a loop to copy a result row from number of worksheets to a new worksheet

Good afternoon,
I am trying to read number of csv files and load them in a new workbook. Then created codes to find the largest number from each column (i.e. maximum value) and pasted in the bottom of each column. I have completed up to the stage of calcualting the largest value and pasting in the lastrow with the help of this forum.
Now I am trying to transfer them in a new worksheet that I created and named as result with my code. With previous suggestions I have figured out how to paste a specific range from one column to another worksheet with the following example:
Sub OneCell()
Sheets("Result").Range("E3:V3").Value = Sheets("HP5_1gs_120_2012.plt").Range("E3:V3").Value
End Sub
But not sure how can I loop this with my existing codes to read the last row where my max values are (highlighted in yellow in figure 1) and paste to the result sheet with the header from column E to the last available column and the rowname as the worksheet name. My data structure will be same for each worksheet for each run. And my start column is always column "E" but the end column (i.e. the last column) can be different for each run. THis is what I am getting really confused of how do I loop thorugh this. So for an example a simple dataset like below (Figure 1):
I am trying to achieve this (figure 2):
my main codes are as below:
Private Sub FilePath_Button_Click()
get_folder
End Sub
Private Sub Run_Button_Click()
load_file
End Sub
Public Sub get_folder()
Dim FolderName As String
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
FolderName = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
TextBox1.Text = FolderName
End Sub
Sub load_file()
Dim strFile As String
Dim ws As Worksheet
Dim test As String
Dim wb As Workbook
test = TextBox1.Text
strFile = Dir(Me.TextBox1.Text & "\*.csv")
Set wb = Workbooks.Add
'added workbook becomes the activeworkbook
With wb
Do While Len(strFile) > 0
Set ws = ActiveWorkbook.Sheets.Add
ws.Name = strFile
With ws.QueryTables.Add(Connection:= _
"TEXT;" & test & "\" & strFile, Destination:=Range("$A$1"))
.Name = strFile
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
strFile = Dir
Loop
End With
Application.DisplayAlerts = False
Worksheets("Sheet1").Delete
Worksheets("Sheet2").Delete
Worksheets("Sheet3").Delete
Application.DisplayAlerts = True
Dim ws1 As Worksheet
Dim ColNo As Long, lc As Long
Dim lastrow As Long
For Each ws1 In ActiveWorkbook.Worksheets
lastrow = Range("A1").End(xlDown).Row
lc = ws1.Cells(1, Columns.Count).End(xlToLeft).Column
For ColNo = 5 To lc
ws1.Cells(lastrow + 2, ColNo).Formula = "=MAX(" & Split(Cells(, ColNo).Address, "$")(1) & "1:" & Split(Cells(, ColNo).Address, "$")(1) & lastrow & ")"
Next ColNo
Next ws1
Dim ws2 As Worksheet
Set ws2 = Sheets.Add
Sheets.Add.Name = "Result"
MsgBox "Job Complete"
End Sub
Private Sub UserForm_Click()
End Sub
I hope I have managed to explain what I am trying to acheive and I would really appreciate any guidence with this. Thanks
Something like the below should do it. No doubt you will want to tweak bits but the general structure is there. I have commented what each block is doing - make sure you understand each line.
But normally for asking questions you should really really break the question down into its parts.
Like - "How do I loop through sheets", then "How do I find the last row of a sheet", then "How do I copy ranges" etc.
You would find that every single one of those has been asked before so in fact a little searching of Stackoverflow would be all that is needed.
Sub example()
Dim ws As Worksheet, dWs As Worksheet 'variables for ws enumerator and destination ws
Dim wb As Workbook 'variable to define the workbook context
Dim sRng As Range, dRng As Range 'variables for source range and destination range
Set wb = ActiveWorkbook
'Add the results sheet and assign our current row range
Set dWs = wb.Worksheets.Add
Set dRng = dWs.Cells(2, 1)
'Change the results sheet name (error if name exists so trap it)
On Error Resume Next
dWs.Name = "Result"
On Error GoTo 0
'Loop worksheets
For Each ws In wb.Worksheets
'Only work on the .csv sheet names
If ws.Name Like "*.csv" Then
'Find the row with the values on
Set sRng = ws.Cells(ws.Rows.Count, 4).End(xlUp)
'And set the range to be to the contiguous cells to the right
Set sRng = ws.Range(sRng, sRng.End(xlToRight))
'Add the sheet name to the results col A
dRng.Value = ws.Name
'Copy sRng to the output range
sRng.Copy dRng(1, 2)
'Increment output row to the next one
Set dRng = dRng(2, 1)
End If
Next ws
'Now just add the headers
For Each dRng In dWs.Range(dWs.Cells(1, 2), dWs.Cells(1, dWs.Cells.Find("*", , XlFindLookIn.xlFormulas, , XlSearchOrder.xlByColumns, xlPrevious).Column))
dRng.Value = "data " & dRng.Column - 1
Next
End Sub