I have a set of Excel spreadsheets to summarise. My sheets are numbered:
xxx-yy-zzzz; xxx-yy-zzz+1; etc.
I would like a reporting spreadsheet to retrieve information each time it is opened. I don't mind doing it with VBA or with formulae.
I've the macro below. I need to auto increment until it runs out of spreadsheets. All the files will be in the same folder, this file can be in any folder.
Sub Macro1()
'
' Macro1 Macro
' autopop
'
'
Range("C4").Select
ActiveCell.FormulaR1C1 = "='[413-05-001.xlsx]Cover'!R4C5"
Range("D4").Select
ActiveCell.FormulaR1C1 = "='[413-05-001.xlsx]Cover'!R5C3"
Range("E4").Select
ActiveCell.FormulaR1C1 = "='[413-05-001.xlsx]Order'!R27C9"
Range("F4").Select
ActiveCell.FormulaR1C1 = "='[413-05-001.xlsx]Cover'!R8C9"
End Sub
Siddharth's method above worked very well for when we were using very simple file names, but it got a lot harder when there were additions made to the filename... So i did some surfing and found a basis of a "list all files and put them in a worksheet" and using some of the code from Siddharth's answer above (thank you very much Mr. Siddharth) and the example i found online here http://alanmurray.blogspot.com/2013/08/excel-vba-list-all-excel-files-in-folder.html , i have finalised my code, and my little VBA app now does what i want - it opens a folder and goes through and pulls out particular cells and creates a summary report in seconds -> will save me hours of tedious work...
Code:
Sub ImportFileList()
Dim MyFolder As String 'Store the folder selected by the using
Dim FiletoList As String 'store the name of the file ready for listing
Dim NextRow As Long 'Store the row to write the filename to
On Error Resume Next
Application.ScreenUpdating = False
'Display the folder picker dialog box for user selection of directory
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Please select a folder"
.Show
.AllowMultiSelect = False
If .SelectedItems.Count = 0 Then
MsgBox "You did not select a folder"
Exit Sub
End If
MyFolder = .SelectedItems(1) & "\"
End With
'Dir finds the first Excel workbook in the folder
FiletoList = Dir(MyFolder & "*.xls")
Range("A1").Value = "Filename"
Range("B1").Value = "Purchase Order Number"
Range("C1").Value = "Vendor"
Range("D1").Value = "Date of PO"
Range("E1").Value = "Currency"
Range("F1").Value = "Subtotal"
Range("G1").Value = "VAT"
Range("H1").Value = "Total"
Range("A1:H1").Font.Bold = True
'Find the next empty row in the list
NextRow = Application.CountA(Range("A:A")) + 1
NextRow = NextRow + 1 ' skip a line
'Do whilst the dir function returns an Excel workbook
Do While FiletoList <> ""
Cells(NextRow, 1).Value = FiletoList 'Write the filename into the next available cell
Cells(NextRow, 2).Formula = "='[" & FiletoList & "]Cover'!R4C4" ' Cover is the excel sheet name
Cells(NextRow, 3).Formula = "='[" & FiletoList & "]Cover'!R6C3"
Cells(NextRow, 4).Formula = "='[" & FiletoList & "]Cover'!R4C7"
Cells(NextRow, 5).Formula = "='[" & FiletoList & "]Cover'!R21C4"
Cells(NextRow, 6).Formula = "='[" & FiletoList & "]Cover'!R19C5"
Cells(NextRow, 7).Formula = "='[" & FiletoList & "]Cover'!R20C5"
Cells(NextRow, 8).Formula = "='[" & FiletoList & "]Cover'!R21C5"
NextRow = NextRow + 1 'Move to next row
FiletoList = Dir 'Dir returns the next Excel workbook in the folder
Loop
Application.ScreenUpdating = True
End Sub
Is this what you are trying? (UNTESTED)
'~~> Change this to the directory which has .xlsx files
Const sDir = "C:\Temp\"
Sub Sample()
Dim ws As Worksheet
Dim i As Long, num As Long, Calcmode As Long
Dim FilesCount As Long, startNum As Long
On Error GoTo Whoa
Set ws = ThisWorkbook.Sheets("Sheet1")
With Application
.ScreenUpdating = False
Calcmode = .Calculation
.Calculation = xlCalculationManual
End With
'~~> Get the number of files in that directory
FilesCount = getFileCount(sDir)
startNum = 1
If FilesCount <> 0 Then
With ws
For i = 4 To (FilesCount + 3)
num = Format(startNum, "000")
.Range("C" & i).Formula = "='[413-05-" & num & ".xlsx]Cover'!R4C5"
.Range("D" & i).Formula = "='[413-05-" & num & ".xlsx]Cover'!R5C3"
.Range("E" & i).Formula = "='[413-05-" & num & ".xlsx]Order'!R27C9"
.Range("F" & i).Formula = "='[413-05-" & num & ".xlsx]Cover'!R8C9"
startNum = startNum + 1
Next i
End With
End If
LetsContinue:
With Application
.ScreenUpdating = True
.Calculation = Calcmode
End With
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
Function getFileCount(s As String) As Long
Dim Path As String, Filename As String
Dim Count As Long
Path = s & "*.xlsx"
Filename = Dir(Path)
Do While Filename <> ""
Count = Count + 1
Filename = Dir()
Loop
getFileCount = Count
End Function
Related
I have written a quite complex VBA script to run on a Word document to
transform it into an email body (together with a bunch of other documents),
combine it with other documents and save as pdf-attachment,
open email-distribution lists
create outlook items and put the distribution lists into a bcc field and body from earlier document
The script worked quite fine until it stopped for unclear to me reason. A "Run-time error '1001': Method 'Range' of object '_Global' failed." started to occur in the "Step 3 ...", specifically in the second line:
objLista.Worksheets(1).Activate
last_row = Range("A1").End(xlDown).Row
The script activates the worksheet just fine, but fails to do anything else with it. I tried to use explicit names of the workbook and worksheet in question, but it didn't help. The same lines in different yet similar script still work well. So I find it hard to find the source of the problem and correct it. I use MS Windows 10, and Office 365.
The whole script below:
Sub script()
' >>>>>>>>>>>>>>>>>>>>>>> Step 0. Declaration of variables and paths <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Dim Disclaimer_Path As String
Dim Email_Path As String
Dim objOutlook As Object
Dim objMail As Object
Dim ExcelApp As Excel.Application
Dim objLista As Workbook
Dim Today As String
Today = Format(Date, "yyyymmdd")
Disclaimer_Path = ...
Email_Path = "!_email.docx"
Distribution_list_Path = "!_List.xlsm"
Distribution_list_Path = "!_List_2.xlsm"
Pdf_Path = ...
Set objOutlook = CreateObject("Outlook.Application")
Set ExcelApp = New Excel.Application
' >>>>>>>>>>>>>>>>>>>>>>> Step 1. Creating e-mail body <<<<<<<<<<<<<<<<<<<<<<<<<<<
' First creating an email-body
Documents.Open FileName:=ActiveDocument.Path & "\1_News.docx"
Documents.Open FileName:=ActiveDocument.Path & "\2_Essay.docx"
Documents.Open FileName:=ActiveDocument.Path & "\3_Comment.docx"
Documents.Open FileName:=Disclaimer_Path
Documents.Open FileName:=Email_Path
Documents("1_News.docx").Activate
Selection.WholeStory
Selection.Copy
Documents("!_Email.docx").Activate
With Selection
.MoveDown
.MoveDown
.PasteAndFormat wdPasteDefault
End With
Documents("2_Essay.docx").Activate
Selection.WholeStory
Selection.Copy
Documents("!_Email.docx").Activate
Selection.PasteAndFormat wdPasteDefault
Documents("3_Comment.docx").Activate
Selection.WholeStory
Selection.Copy
Documents("!_Email.docx").Activate
With Selection
.PasteAndFormat wdPasteDefault
.WholeStory
End With
' Cleaning
Documents("2_Essay.docx").Close SaveChanges:=wdDoNotSaveChanges
Documents("3_Comment.docx").Close SaveChanges:=wdDoNotSaveChanges
Documents("Disclaimer.docx").Close SaveChanges:=wdDoNotSaveChanges
Stop
' >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Step 2. Creation of pdf <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Documents("1_News.docx").Activate
Selection.WholeStory
Selection.Copy
ThisDocument.Activate
With Selection
'.Range.Text = vbNewLine
.MoveDown
.PasteAndFormat wdPasteDefault
.Range.Text = vbNewLine
.MoveDown
End With
ActiveDocument.ActiveWindow.View.Type = wdMasterView
With ActiveDocument.Subdocuments
.AddFromFile Name:=ActiveDocument.Path & "\2_Essay.docx"
.AddFromFile Name:=ActiveDocument.Path & "\3_Comment.docx"
.AddFromFile Name:=ActiveDocument.Path & "\4_Preview.docx"
.AddFromFile Name:=ActiveDocument.Path & "\5_Comment_2.docx"
.AddFromFile Name:=ActiveDocument.Path & "\8_Calendar.docx"
.AddFromFile Name:=Disclaimer_Path
End With
'Returns to standard view
ActiveDocument.ActiveWindow.View.Type = wdPrintView
Selection.HomeKey Unit:=wdStory
Stop
ActiveDocument.ExportAsFixedFormat Pdf_Path, wdExportFormatPDF
' >>>>>>>>>>>>>>>>>>>>>>>> Step 3. Creating Distribution lists <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Set objLista = ExcelApp.Workbooks.Open(Distribution_list_Path)
ExcelApp.Visible = True
Dim lista_1 As String, lista_2 As String, lista_3 As String, lista_4 As String, lista_5 As String, lista_6 As String, lista_7 As String, lista_8 As String, lista_9 As String
lista_1 = ""
lista_2 = ""
lista_3 = ""
lista_4 = ""
lista_5 = ""
lista_6 = ""
lista_7 = ""
lista_8 = ""
lista_9 = ""
objLista.Worksheets(1).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_1 = lista_1 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(2).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_2 = lista_2 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(3).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_3 = lista_3 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(4).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_4 = lista_4 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(5).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_5 = lista_5 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(6).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_6 = lista_6 & "; " & Cells(i, 1).Value
Next i
' Now differentr set of lists
Set objLista_2 = ExcelApp.Workbooks.Open(Distribution_list_Path_2)
objLista_2.Worksheets(1).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_7 = lista_7 & "; " & Cells(i, 1).Value
Next i
objLista_2.Worksheets(2).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_8 = lista_8 & "; " & Cells(i, 1).Value
Next i
objLista_2.Worksheets(3).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_9 = lista_9 & "; " & Cells(i, 1).Value
Next i
' >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Step 4. Creates e-mails <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Documents("!_Email.docx").Activate
Selection.Copy
For Each Item In Array(lista_1, lista_2, lista_3, lista_4, lista_5, lista_6, lista_7, lista_8, lista_9)
With objOutlook.CreateItem(0)
oAccount = ""
.bcc = Item
.Subject = "Weekly"
.Attachments.add Pdf_Path
Set Editor = .GetInspector.WordEditor
Editor.Content.Paste
.Display
End With
Next Item
'Cleaning
Documents("1_News.docx").Close SaveChanges:=wdDoNotSaveChanges
Documents("!_email.docx").Close SaveChanges:=wdDoNotSaveChanges
Workbooks("!_List.xlsm").Worksheets("List_1").Activate
Range("A1").Select 'To żeby uniknąć jednego z błędów, który się wcześniej wywalał, gdy arkusz był zamykany z kursorem w innym miejscu niż "A1"
Workbooks("!_List.xlsm").Close SaveChanges:=wdDoNotSaveChanges
Workbooks("!_List_2.xlsm").Worksheets(1).Activate
Range("A1").Select 'To żeby uniknąć jednego z błędów, który się wcześniej wywalał, gdy arkusz był zamykany z kursorem w innym miejscu niż "A1"
Workbooks("!_List_2.xlsm").Close SaveChanges:=wdDoNotSaveChanges
End Sub
I inherited VBA code that has not worked since my work updated our version of Excel.
The original code looped through all Excel files in a specific folder.
If data in specific cells was blank or a 0, would rename the whole workbook so I would know what files to delete after the fact.
This is the original code. I don't need it to do all of this anymore.
This is part one:
Sub AllFilesWeekly()
Dim folderPath As String
Dim filename As String
Dim wb As Workbook
folderPath = "C:\Users\" & (Environ$("Username")) & "\Desktop\Process Production\" 'change to suit
If Right(folderPath, 1) <> "\" Then folderPath = folderPath + "\"
filename = Dir(folderPath & "*.xlsx")
Do While filename <> ""
Application.ScreenUpdating = False
Set wb = Workbooks.Open(folderPath & filename)
'Call a subroutine here to operate on the just-opened workbook
Call getmetrics
On Error Resume Next
If Not ActiveWorkbook.Name Like "Audit Hub Report Distribution*" Then
ActiveWorkbook.Close
End If
filename = Dir
Loop
Application.ScreenUpdating = True
End Sub
The second part:
Sub getmetrics()
Dim cell As Range
Dim procstring As String, wbname As String
'Dim OQAYTD As String
Dim OQAMTD As String
Dim ORLYTD As String
Dim ORLMTD As String
Dim DR As String
Dim Audits As Long
Dim permonth As String, peryear As String, permonthrl As String, peryearrl As String
Dim RS As Worksheet, AD As Worksheet, QD As Worksheet, ws As Worksheet, YN As Boolean
For Each ws In Worksheets
If ws.Name = "Audit Detail" Then
YN = True
End If
Next ws
If YN = True Then
ActiveWorkbook.Sheets(2).Name = ("Rep Summary")
Set RS = ActiveWorkbook.Sheets("Rep Summary")
Set AD = ActiveWorkbook.Sheets("Audit Detail")
Set QD = ActiveWorkbook.Sheets("Question Detail")
With Sheets("Process Summary")
For Each cell In Range(Range("A3"), Range("A9999").End(xlUp))
If cell.Value = "Record Level YTD" Then
ORLYTD = Range(cell.Address).Offset(0, 1).Value
Else
If cell.Value = "YTD Quality Average" Then
OQAYTD = Range(cell.Address).Offset(0, 1).Value
Else
If cell.Value = "Record Level Quality Average" Then
ORLMTD = Range(cell.Address).Offset(0, 1).Value
Else
If cell.Value = "Quality Average" Then
OQAMTD = Range(cell.Address).Offset(0, 1).Value
Else
If cell.Value = "Audits" Then
Audits = Range(cell.Address).Offset(0, 1).Value
End If
End If
End If
End If
End If
Next cell
End With
wbname = Left(ActiveWorkbook.Name, Len(ActiveWorkbook.Name) - 4)
peryear = VBA.Format(OQAYTD, "Percent")
permonth = VBA.Format(OQAMTD, "Percent")
peryearrl = VBA.Format(ORLYTD, "Percent")
permonthrl = VBA.Format(ORLMTD, "Percent")
DR = Right(Sheets("Process Summary").Range("A2").Value, Len(Sheets("Process
Summary").Range("A2").Value) - 12)
RS.Range(RS.Range("A1"), RS.Range("IV1").End(xlToLeft)).AutoFilter
RS.Range(RS.Range("A1"), RS.Range("IV1").End(xlToLeft)).EntireColumn.AutoFit
AD.Range(AD.Range("A1"), AD.Range("IV1").End(xlToLeft)).AutoFilter
AD.Range(AD.Range("A1"), AD.Range("IV1").End(xlToLeft)).EntireColumn.AutoFit
QD.Range(QD.Range("A1"), QD.Range("IV1").End(xlToLeft)).AutoFilter
QD.Range(QD.Range("A1"), QD.Range("IV1").End(xlToLeft)).EntireColumn.AutoFit
Application.DisplayAlerts = False
procstring = wbname & "|" & permonth & "|" & Audits & "|" & peryear & "|" & permonthrl & "|" &
peryearrl & "|" & DR ' & "|" & Users
Debug.Print procstring
Else
Application.DisplayAlerts = False
Dim AWN As String
AWN = ActiveWorkbook.FullName
Debug.Print "Not Audited: " & ActiveWorkbook.Name
ActiveWorkbook.SaveAs "C:\Users\" & (Environ$("Username")) & "\Desktop\Process Production\Delete -" & Second(Now)
Kill AWN
ActiveWorkbook.Close savechanges:=True
Application.DisplayAlerts = True
End If
End Sub
All I need to do is look at cell D3 on the "Process Summary" tab.
If the value in that space is "0.00%", rename the workbook to delete and loop on until all workbooks are looked at.
I do not need to screen print all the extra numbers any more.
Build a Collection of filenames that match the criteria and then use it to rename the files.
Option Explicit
Sub AllFilesWeekly()
Dim folderPath As String, filename As String
Dim wb As Workbook, ws As Worksheet
Dim col As Collection, n As Long
Set col = New Collection
folderPath = "C:\Users\" & (Environ$("Username")) & "\Desktop\Process Production\" 'change to suit
If Right(folderPath, 1) <> "\" Then folderPath = folderPath + "\"
' scan folder
filename = Dir(folderPath & "*.xlsx")
Do While filename <> ""
Set wb = Workbooks.Open(folderPath & filename, True, True) ' update links, readonly
For Each ws In wb.Sheets
If ws.Name = "Process Summary" Then
If Format(ws.Range("D3"), "0.00%") = "0.00%" Then
col.Add wb.Name
End If
End If
Next
wb.Close
n = n + 1
filename = Dir
Loop
' result
MsgBox "Files scanned = " & n & vbCrLf & _
"To delete = " & col.Count, vbInformation, folderPath
' rename
If col.Count > 0 Then
If MsgBox("Continue to rename ?", vbYesNo) = vbYes Then
For n = 1 To col.Count
Name folderPath & col(n) As folderPath & "delete_" & col(n)
Next
MsgBox "Rename done"
End If
End If
End Sub
I am trying to generate CSV files from a set of records from Excel.
Column A is the file name and the rest of the columns are the data to write to the the file.
As of now, I am using WriteLine, but it doesn't work as expected:
As you can see, I don't get the expected output. How do I get the expected output?
Private Sub ommandButton1_Click()
Dim Path As String
Dim Folder As String
Dim Answer As VbMsgBoxResult
Path = "C:\Access Permissions\Users"
Folder = Dir(Path, vbDirectory)
If Folder = vbNullString Then
'-------------Create Folder -----------------------
MkDir ("C:\Access Permissions")
MkDir ("C:\Access Permissions\Roles")
MkDir ("C:\Access Permissions\Users")
Else
Set rngSource = Range("A4", Range("A" & Rows.Count).End(xlUp))
rngSource.Copy Range("AA1")
Range("AA:AA").RemoveDuplicates Columns:=1, Header:=xlNo
Set rngUnique = Range("AA1", Range("AA" & Rows.Count).End(xlUp))
Set lr = Cells(rngSource.Rows.Count, rngSource.Column)
Set fso = CreateObject("Scripting.FileSystemObject")
For Each cell In rngUnique
n = Application.CountIf(rngSource, cell.Value)
Set C = rngSource.Find(cell.Value, lookat:=xlWhole, after:=lr)
Set oFile = fso.CreateTextFile("C:\Access Permissions\Users\" & cell.Value & "-Users.csv")
For i = 1 To n
oFile.WriteLine C.Offset(0, 1).Value
oFile.WriteLine C.Offset(0, 2).Value
oFile.WriteLine C.Offset(0, 3).Value
oFile.WriteLine C.Offset(0, 4).Value
oFile.WriteLine C.Offset(0, 6).Value
oFile.WriteLine C.Offset(0, 7).Value
Set C = rngSource.FindNext(C)
Next i
Next cell
rngUnique.ClearContents
MsgBox "Individual Users.csv files got generated" & vbCrLf & " " & vbCrLf & "Path - C:\Access Permissions\Groups "
End If
End Sub
Updated Image:
Let me re-phrase my questions.
Updated Image Enclosed.
Using the Data Set [Updated Image point 1], It creates unique CSV files based on column A.
File got saved at the path given.
As of now the row data associated with each file name got written in the files but in a new line manner.
As expected, how the output can be written in Columns.[ Updated Image Point 4]
Given code is working without any error.
5.1. I just need to click twice if the Path folder does not exist.
5.2. at first click, it creates the Folder at the given path.
5.3. at Second click it generates the unique files, with its records.
If you can please guide me on how the records can be written in columns [ Updated Image Point 4 ], expected output.
Download File
I assume your data does not contain any semicolons.
You are writing each field on a line by itself. Instead, join the fields on a single line:
oFile.WriteLine C.Offset(0, 1).Value & ";" & _
C.Offset(0, 2).Value & ";" & _
C.Offset(0, 3).Value & ";" & _
C.Offset(0, 4).Value & ";" & _
C.Offset(0, 6).Value & ";" & _
C.Offset(0, 7).Value
There are other bugs in your example; it should not work as far as I can see. For example, you keep opening the same file with CreateTextFile. You should only create a file once, not every time you write to it. According to the documentation, you should get an error on your second try, see CreateTextFile method. The reason you don't get an error is probably because you never close the file. You should close the files you create.
I would use this approach instead:
' Collect the data for each file into a dictionary.
' The cells in the table must not contain semicolons.
Sub Doit()
Dim Sht As Worksheet
Dim Rng As Range
Dim LastRowNum As Long, LastColNum As Long
Dim Lst As Variant, Hdr As Variant, Elem As Variant
Dim Idx As Long, Idx2 As Long
Dim Dct As Object
Dim HdrTxt, Txt As String, Sep As String
Dim Filename As String
Set Sht = ActiveSheet
' Get the last row in column 1
Set Rng = Sht.Cells(Sht.Rows.Count, 1).End(xlUp)
LastRowNum = Rng.Row
' Get the last column in row 3
Set Rng = Sht.Cells(3, Sht.Columns.Count).End(xlToLeft)
LastColNum = Rng.Column
' Get the headers in row 3
Set Rng = Sht.Range(Sht.Cells(3, 1), Sht.Cells(3, LastColNum))
Hdr = Rng
' Create a semicolon seprated line for the headers
HdrTxt = ""
Sep = ""
For Idx = LBound(Hdr, 2) To UBound(Hdr, 2)
HdrTxt = HdrTxt & Sep & Hdr(1, Idx)
Sep = ";"
Next Idx
HdrTxt = HdrTxt & vbNewLine
' Get the data from row 4 and down
Set Rng = Sht.Range(Sht.Cells(4, 1), Sht.Cells(LastRowNum, LastColNum))
Lst = Rng
' Store the data for each file in a dicitonary
Set Dct = CreateObject("Scripting.Dictionary")
For Idx = LBound(Lst) To UBound(Lst)
Filename = Lst(Idx, 1)
' Create a semicolon seprated line
Txt = ""
Sep = ""
For Idx2 = LBound(Lst, 2) To UBound(Lst, 2)
Txt = Txt & Sep & Lst(Idx, Idx2)
Sep = ";"
Next Idx2
Txt = Txt & vbNewLine
' Add the line to the dictionary
If Dct.Exists(Filename) Then
Dct(Filename) = Dct(Filename) & Txt
Else
Dct(Filename) = HdrTxt & Txt
End If
Next Idx
' Output data for each file to the immdiate window
For Each Elem In Dct
' Change this to open the file and write the contents
Debug.Print "---- Filename: " & Elem
Debug.Print Dct(Elem)
Next Elem
End Sub
The example makes sure you only create the files once:
Change the last loop For Each Elem In Dct that prints the data to the immediate window, to create a file instead. Use the Write method instead of the WriteLine method, as the data already contains the line-breaks. And remember to Close the files.
I think this is what you want.
Sub Copy_To_Workbooks()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim MyPath As String
Dim foldername As String
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
'Set filter range on ActiveSheet: A1 is the top left cell of your filter range
'and the header of the first column, D is the last column in the filter range.
'You can also add the sheet name to the code like this :
'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
'No need that the sheet is active then when you run the macro when you use this.
Set My_Range = Range("A1:B" & LastRow(ActiveSheet))
My_Range.Parent.Select
If ActiveWorkbook.ProtectStructure = True Or _
My_Range.Parent.ProtectContents = True Then
MsgBox "Sorry, not working when the workbook or worksheet is protected", _
vbOKOnly, "Copy to new workbook"
Exit Sub
End If
'This example filters on the first column in the range(change the field if needed)
'In this case the range starts in A so Field:=1 is column A, 2 = column B, ......
FieldNum = 1
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
'Set the file extension/format
If Val(Application.Version) < 12 Then
'You use Excel 97-2003
FileExtStr = ".txt": FileFormatNum = -4143
Else
'You use Excel 2007-2010
If ActiveWorkbook.FileFormat = 56 Then
FileExtStr = ".txt": FileFormatNum = 56
Else
FileExtStr = ".txt": FileFormatNum = 51
End If
End If
'Change ScreenUpdating, Calculation, EnableEvents, ....
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
'Delete the sheet RDBLogSheet if it exists
On Error Resume Next
Application.DisplayAlerts = False
Sheets("RDBLogSheet").Delete
Application.DisplayAlerts = True
On Error GoTo 0
' Add worksheet to copy/Paste the unique list
Set ws2 = Worksheets.Add(After:=Sheets(Sheets.Count))
ws2.Name = "RDBLogSheet"
'Fill in the path\folder where you want the new folder with the files
'you can use also this "C:\Users\Ron\test"
MyPath = "C:\Users\ryans\OneDrive\Desktop\"
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'Create folder for the new files
foldername = MyPath & Format(Now, "yyyy-mm-dd hh-mm-ss") & "\"
MkDir foldername
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A3"), Unique:=True
'loop through the unique list in ws2 and filter/copy to a new sheet
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In .Range("A4:A" & Lrow)
'Filter the range
My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
'Check if there are no more then 8192 areas(limit of areas)
CCount = 0
On Error Resume Next
CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
.Areas(1).Cells.Count
On Error GoTo 0
If CCount = 0 Then
MsgBox "There are more than 8192 areas for the value : " & cell.Value _
& vbNewLine & "It is not possible to copy the visible data." _
& vbNewLine & "Tip: Sort your data before you use this macro.", _
vbOKOnly, "Split in worksheets"
Else
'Add new workbook with one sheet
Set WSNew = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
'Copy/paste the visible data to the new workbook
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
' Paste:=8 will copy the columnwidth in Excel 2000 and higher
' Remove this line if you use Excel 97
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
'Save the file in the new folder and close it
On Error Resume Next
ChDir MyPath
ActiveWorkbook.SaveAs Filename:= _
foldername & cell.Value & ".txt", _
FileFormat:=xlTextMSDOS, CreateBackup:=False
If Err.Number > 0 Then
Err.Clear
ErrNum = ErrNum + 1
WSNew.Parent.SaveAs foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr, FileFormatNum
.Cells(cell.Row, "B").Formula = "=Hyperlink(""" & foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr & """)"
.Cells(cell.Row, "A").Interior.Color = vbRed
Else
.Cells(cell.Row, "B").Formula = _
"=Hyperlink(""" & foldername & cell.Value & FileExtStr & """)"
End If
WSNew.Parent.Close False
On Error GoTo 0
End If
'Show all the data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
.Cells(1, "A").Value = "Red cell: can't use the Unique name as file name"
.Cells(1, "B").Value = "Created Files (Click on the link to open a file)"
.Cells(3, "A").Value = "Unique Values"
.Cells(3, "B").Value = "Full Path and File name"
.Cells(3, "A").Font.Bold = True
.Cells(3, "B").Font.Bold = True
.Columns("A:B").AutoFit
End With
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
If ErrNum > 0 Then
MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
& vbNewLine & "There are characters in the name that are not allowed" _
& vbNewLine & "in a sheet name or the worksheet already exist."
End If
'Restore ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
ws2.Select
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Before:
After:
I have a macro that imports csv-files into sheets with the same name in a workbook. All the csv files end with ".csv" except for one file which ends with ".CSV". The macro is importing the csv files that end with ".csv" fine. But when it encounters the csv file with ".CSV" it adds a new sheet. I think it's a matter of deactiviting the case sensivity (and I've tried) but I'm not sure. Here's the code:
Private Sub importOrUpdate(opr$)
Dim csvFile, csvArr
Dim wsCSV As Worksheet, wsImport As Worksheet
Dim importFolder$, cnt%, i%
Dim csvName$, idx%, arr, shName$
Dim processed$
U.Start
processed = "|"
csvArr = selectFiles
For i = 0 To UBound(csvArr)
'Workbooks.Open csvArr(i), False, True
Call importToTempSheet(csvArr(i))
Set wsCSV = Tempsheet
idx = InStrRev(csvArr(i), "\") + 1
csvName = Mid(csvArr(i), idx)
csvName = Replace(csvName, ".csv", "")
arr = Split(csvName, "_")
If UBound(arr) = 2 Then
shName = arr(1) & "_" & arr(2)
Else
shName = csvName
End If
On Error Resume Next
Set wsImport = ThisWorkbook.Sheets(shName)
On Error GoTo 0
If wsImport Is Nothing Then
ThisWorkbook.Sheets.Add before:=Sheet14
Set wsImport = ActiveSheet
wsImport.Tab.Color = 5296274
wsImport.Name = shName
Call import(wsCSV, wsImport)
ElseIf opr = "Update" Then
Call update(wsCSV, wsImport)
ElseIf InStr(1, processed, "|" & shName & "|", vbTextCompare) > 0 Then
Call update(wsCSV, wsImport)
Else
Call import(wsCSV, wsImport)
End If
Call updateFormula(wsImport)
processed = processed & shName & "|"
cnt = cnt + 1
'wsCSV.Parent.Close False
Next
Sheet14.Activate
U.Finish
MsgBox cnt & " files imported/updated", vbInformation
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub importToTempSheet(filePath)
Dim lRow&
Tempsheet.Cells.Clear
Dim wsCSV As Worksheet
Workbooks.Open filePath, False, True
Set wsCSV = ActiveWorkbook.Sheets(1)
lRow = wsCSV.Cells(Rows.Count, "A").End(xlUp).Row
wsCSV.Range("A1:A" & lRow).Copy
Tempsheet.Range("A1").PasteSpecial xlPasteValues
Application.CutCopyMode = False
wsCSV.Parent.Close
Tempsheet.Range("A1:A" & lRow).TextToColumns Tempsheet.Range("A1"), xlDelimited, xlTextQualifierNone, False, False, True, False, False
With Tempsheet
.Range("A:A").NumberFormat = "m/d/yyyy"
convertToDate .Range("A2", .Cells(Rows.Count, "A").End(xlUp))
End With
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function selectFiles()
With Application.FileDialog(msoFileDialogFilePicker)
.Title = "Select CSV Files"
.ButtonName = "Select"
.AllowMultiSelect = True
.Filters.Clear
.Filters.Add "Excel Files", "*.csv"
.InitialFileName = ThisWorkbook.Path & "\"
.Show
If .SelectedItems.Count = 0 Then
End
Else
Dim csvArr, i%
ReDim csvArr(.SelectedItems.Count - 1)
For i = 1 To .SelectedItems.Count
csvArr(i - 1) = .SelectedItems(i)
Next
selectFiles = csvArr
End If
End With
End Function
The issue is with the replace
try..
csvName = Replace(LCase(csvName), ".csv", "")
or use two replaces...
csvName = Replace(csvName, ".csv", "")
csvName = Replace(csvName, ".CSV", "")
I have a macro that needs to open a few excel files and copy data from those files and paste them into the macro file in a sheet named "Consolidated".
The macro goes to a specified path, counts the number of files in the folder and then loops through to open a file, copy the contents and then save and close the file.
The macro runs perfectly on my system but not on the users systems.
The error i am receiving during the looping process is "Runtime Error '9' Subscript out of range". The line on which this error pops up is
Set wb = Workbooks.Open(Filename:=.FoundFiles(file_count))
At first i thought that the files might be opening slower than the code execution so i added wait time of 5 seconds before and after the above line...but to no avail.
The code is listed below
Sub grab_data()
Application.ScreenUpdating = False
Dim rng As Range
srow = ThisWorkbook.Sheets("Consolidated Data").Cells(65536, 11).End(xlUp).Row
'Number of filled rows in column A of control Sheet
ThisWorkbook.Sheets("Control Sheet").Activate
rawfilepth = Sheets("Control Sheet").Cells(65536, 1).End(xlUp).Row
'Loop to find the number of excel files in the path in each row of the Control Sheet
For folder_count = 2 To rawfilepth
wkbpth = Sheets("Control Sheet").Cells(folder_count, 1).Value
With Application.FileSearch
.LookIn = wkbpth
.FileType = msoFileTypeExcelWorkbooks
.Execute
filecnt = .FoundFiles.Count
'Loop to count the number of sheets in each file
For file_count = 1 To filecnt
Application.Wait (Now + TimeValue("0:00:05"))
Set wb = Workbooks.Open(Filename:=.FoundFiles(file_count))
Application.Wait (Now + TimeValue("0:00:05"))
filenm = ActiveWorkbook.Name
For sheet_count = 1 To Workbooks(filenm).Sheets.Count
If Workbooks(filenm).Sheets(sheet_count).Name <> "Rejected" Then
Workbooks(filenm).Sheets(sheet_count).Activate
ActiveSheet.Columns("a:at").Select
Selection.EntireColumn.Hidden = False
shtnm = Trim(ActiveSheet.Name)
lrow = ActiveSheet.Cells(65536, 11).End(xlUp).Row
If lrow = 1 Then lrow = 2
For blank_row_count = 2 To lrow
If ActiveSheet.Cells(blank_row_count, 39).Value = "" Then
srow = ActiveSheet.Cells(blank_row_count, 39).Row
Exit For
End If
Next blank_row_count
For uid = srow To lrow
ActiveSheet.Cells(uid, 40).Value = ActiveSheet.Name & uid
Next uid
ActiveSheet.Range("a" & srow & ":at" & lrow).Copy
ThisWorkbook.Sheets("Consolidated Data").Activate
alrow = ThisWorkbook.Sheets("Consolidated Data").Cells(65536, 11).End(xlUp).Row
ThisWorkbook.Sheets("Consolidated Data").Range("a" & alrow + 1).Activate
ActiveCell.PasteSpecial xlPasteValues
ThisWorkbook.Sheets("Consolidated Data").Range("z" & alrow + 1).Value = shtnm
ThisWorkbook.Sheets("Consolidated Data").Range("z" & alrow + 1 & ":z" & (alrow+lrow)).Select
Selection.FillDown
ThisWorkbook.Sheets("Consolidated Data").Range("ap" & alrow + 1).Value = wkbpth
ThisWorkbook.Sheets("Consolidated Data").Range("ap" & alrow + 1 & ":ap" & (alrow + lrow)).Select
Selection.FillDown
ThisWorkbook.Sheets("Consolidated Data").Range("ao" & alrow + 1).Value = filenm
ThisWorkbook.Sheets("Consolidated Data").Range("ao" & alrow + 1 & ":ao" & (alrow + lrow)).Select
Selection.FillDown
Workbooks(filenm).Sheets(sheet_count).Activate
ActiveSheet.Range("am" & srow & ":am" & lrow).Value = "Picked"
ActiveSheet.Columns("b:c").EntireColumn.Hidden = True
ActiveSheet.Columns("f:f").EntireColumn.Hidden = True
ActiveSheet.Columns("h:i").EntireColumn.Hidden = True
ActiveSheet.Columns("v:z").EntireColumn.Hidden = True
ActiveSheet.Columns("aa:ac").EntireColumn.Hidden = True
ActiveSheet.Columns("ae:ak").EntireColumn.Hidden = True
End If
Next sheet_count
Workbooks(filenm).Close True
Next file_count
End With
Next folder_count
Application.ScreenUpdating = True
End Sub
Thanks in advance for your help.
First off, make sure you have
Option Explicit
at the top of your code so you can make sure you don't mess any of your variables up. This way, everything is dimensioned at the beginning of your procedure. Also, use variables for your workbooks, it'll clean up the code and make it more understandable, also, use indenting.
This worked for me, I found that I need to make sure the file isn't already open (assuming you aren't using an add-in) so you don't want to open the workbook with the code in it when it is already open):
Sub grab_data()
Dim wb As Workbook, wbMacro As Workbook
Dim filecnt As Integer, file_count As Integer
Application.ScreenUpdating = False
Application.EnableEvents = False
Set wbMacro = ThisWorkbook
With Application.FileSearch
.LookIn = wbMacro.Path
.FileType = msoFileTypeExcelWorkbooks
.Execute
filecnt = .FoundFiles.Count
'Loop to count the number of sheets in each file
For file_count = 1 To filecnt
If wbMacro.FullName <> .FoundFiles(file_count) Then
Set wb = Workbooks.Open(Filename:=.FoundFiles(file_count))
Debug.Print wb.Name
wb.Close True
End If
Next file_count
End With
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Hope that helps.
Try this (hope I didn't mess any of it up), basically, I'm checking to make sure the directory exists also, and I cleaned up the code quite a bit to make it more understandable (mainly for myself):
Sub grab_data()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim i As Long
Dim lRow As Long, lRowEnd As Long, lFolder As Long, lFilesTotal As Long, lFile As Long
Dim lUID As Long
Dim rng As Range
Dim sWkbPath As String
Dim wkb As Workbook, wkbTarget As Workbook
Dim wksConsolidated As Worksheet, wks As Worksheet
Dim v1 As Variant
Set wkb = ThisWorkbook
Set wksConsolidated = wkb.Sheets("Consolidated Data")
'Loop to find the number of excel files in the path in each row of the Control Sheet
For lFolder = 2 To wksConsolidated.Cells(65536, 1).End(xlUp).Row
sWkbPath = wksConsolidated.Cells(lFolder, 1).Value
'Check if file exists
If Not Dir(sWkbPath, vbDirectory) = vbNullString Then
With Application.FileSearch
.LookIn = sWkbPath
.FileType = msoFileTypeExcelWorkbooks
.Execute
lFilesTotal = .FoundFiles.Count
'Loop to count the number of sheets in each file
For lFile = 1 To lFilesTotal
If .FoundFiles(lFile) <> wkb.FullName Then
Set wkbTarget = Workbooks.Open(Filename:=.FoundFiles(lFile))
For Each wks In wkbTarget.Worksheets
If wks.Name <> "Rejected" Then
wks.Columns("a:at").EntireColumn.Hidden = False
lRowEnd = Application.Max(ActiveSheet.Cells(65536, 11).End(xlUp).Row, 2)
v1 = Application.Transpose(wks.Range(Cells(2, 39), Cells(lRowEnd, 39)))
For i = 1 To UBound(v1)
If Len(v1(i)) = 0 Then
lRow = i + 1
Exit For
End If
Next i
v1 = Application.Transpose(wks.Range(Cells(lRow, 40), Cells(lRowEnd, 40)))
For lUID = 1 To UBound(v1)
v1(lUID) = wks.Name & lUID
Next lUID
Application.Transpose(wks.Range(Cells(lRow, 40), Cells(lRowEnd, 40))) = v1
wks.Range("a" & lRow & ":at" & lRowEnd).Copy
i = wksConsolidated.Cells(65536, 11).End(xlUp).Row
With wksConsolidated
.Range("A" & i).PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("z" & i + 1).Value = wks.Name
.Range("z" & i + 1 & ":z" & i + lRowEnd).FillDown
.Range("ap" & i + 1) = sWkbPath
.Range("ap" & i + 1 & ":ap" & i + lRowEnd).FillDown
.Range("ao" & i + 1) = wkbTarget.FullName
.Range("ao" & i + 1 & ":ao" & (i + lRowEnd)).FillDown
End With
With wks
.Range("am" & lRow & ":am" & lRowEnd) = "Picked"
.Columns("b:c").EntireColumn.Hidden = True
.Columns("f:f").EntireColumn.Hidden = True
.Columns("h:i").EntireColumn.Hidden = True
.Columns("v:z").EntireColumn.Hidden = True
.Columns("aa:ac").EntireColumn.Hidden = True
.Columns("ae:ak").EntireColumn.Hidden = True
End With
End If
Next wks
wkbTarget.Close True
End If
Next lFile
End With
End If
Next lFolder
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
End Sub
There may be two issues here
The macro runs perfectly on my system but not on the users systems
I presume you are running this in xl2003 as Application.FileSearch was deprecated in xl2007. So you are probably best advised to use a Dir approach instead to ensure your code works on all machines. Are you users all using xl2003?
You will get a "Object doesn't support this action" error in xl2007/10
The error i am receiving during the looping process is "Runtime Error '9' Subscript out of range
Is this error occuring on your machine, or on one/all of the user machines?
Ok guys,
I have finally been able to figure out the problem.
This error is occuring because some of the files in the raw data folder are corrupted and get locked automatically. So when the macro on opening the file gets an error and stops there.
I have now made a change to the macro. It would now first check if the files are all ok to be imported. If there is a corrupt file then it would list down their names and the user will be required to manually open it and then do a "save As" and save a new version of the corrupt file and then delete it.
Once this is done then the macro does the import of the data.
I am putting down the code below for testing the corrupt files.
Sub error_tracking()
Dim srow As Long
Dim rawfilepth As Integer
Dim folder_count As Integer
Dim lrow As Long
Dim wkbpth As String
Dim alrow As Long
Dim One_File_List As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
ThisWorkbook.Sheets("Control Sheet").Activate
rawfilepth = Sheets("Control Sheet").Cells(65536, 1).End(xlUp).Row
Sheets("Control Sheet").Range("E2:E100").Clear
'Loop to find the number of excel files in the path
'in each row of the Control Sheet
For folder_count = 2 To rawfilepth
wkbpth = Sheets("Control Sheet").Cells(folder_count, 1).Value
One_File_List = Dir$(wkbpth & "\*.xls")
Do While One_File_List <> ""
On Error GoTo err_trap
Workbooks.Open wkbpth & "\" & One_File_List
err_trap:
If err.Number = "1004" Then
lrow = Sheets("Control Sheet").Cells(65536, 5).End(xlUp).Row
Sheets("Control Sheet").Cells(lrow + 1, 5).Value = One_File_List
Else
Workbooks(One_File_List).Close savechanges = "No"
End If
One_File_List = Dir$
Loop
Next folder_count
If Sheets("Control Sheet").Cells(2, 5).Value = "" Then
Call grab_data
Else
MsgBox "Please check control sheet for corrupt file names.", vbCritical, "Corrupt Files Notification"
End If
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
This may not be one of the cleanest codes around, but it gets the job done. For those who have been troubled by this problem this is one of the ways to get around this problem. For those who havae a better way of doing this please respond with your codes.
Thanks to all for helping me out!!!!