Excel copy specific data cell from multiple workbooks to a master file - vba

I have various workbooks with different employee names containing different projectnumbers and hours worked on these projects. I'm trying to get these project numbers filtered out to a master file (zmaster) containing the entire row(s) of a specific project number. I need Excel to filter through the directory (specific folder cointaining all employee hours files) for matches and copy these matches into the zmaster file. The filter is cell A1 of the master file (eg. 300000 in linked picture example). Picture 1 is the master file and picture 2 is an example of the employee hours file.
https://i.stack.imgur.com/OKs68.png (1)
https://i.stack.imgur.com/va2Yn.png (2)
Also, it would be great if Excel would filter out duplicates (eg. week 30 with the exact same hours and employee name already in the master file is most likely duplicate and should be ignored).
I'm pretty new to Excel vba and found/adjusted the following macro's. The first one copies all data from the directory and places it into the master file. The second one filters out the projectnumber matching with cell A1. However, this requires 2 steps and when I run my first macro for the second time it will also collect data already entered into the master file. Also, my second macro places matches in the same row number as where they're placed in the employee hours file and therefore removing earlier observations in the master file placed in the same row (eg. projectnumber 100000 is placed in row 2 of the employee hours file therefore copying to row 2 in the master file, removing the indicator row of the master file).
First macro:
Sub LoopThroughDirectory()
Dim MyFile As String
Dim erow
Dim Filepath As String
Filepath = ("C:\test\”)
MyFile = Dir(Filepath)
Do While Len(MyFile) > 0
If MyFile = "zmaster.xlsx" Then
Exit Sub
End If
Workbooks.Open (Filepath & MyFile)
Range("A2:L9").Copy
ActiveWorkbook.Close
erow = Blad1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Paste Destination:=Worksheets("Sheet1").Range(Cells(erow, 1), Cells(erow, 4))
MyFile = Dir
Loop
End Sub
Second macro:
Sub finddata()
Dim projectnumber As Integer
Dim finalrow As Integer
Dim i As Integer
Sheets("Blad1").Range("A1:H9").ClearContents
projectnumber = Sheets("Blad1").Range("A1").Value
finalrow = Sheets("Blad1").Range("A30").End(x1Up).row
For i = 1 To finalrow
If Cells(i, 1) = projectnumber Then
Range(Cells(i, 1), Cells(i, 12)).Copy
Range("A100").End(x1Up).Offset(1, 0).PasteSpecial x1pasteformulasandnumberformats
End If
Next i
Range("A1").Select
End sub
Hopefully everything is clear and thanks in advance!

This should work.
Open each file in directory
check that the file name is not zmaster and that it contains xlsx
run through each row in the current file and then combine the range for copying to master file
copy to master file last row plus 1, which is the first empty row
Option Explicit
Sub CopyToMasterFile()
Dim MasterWB As Workbook
Dim MasterSht As Worksheet
Dim MasterWBShtLstRw As Long
Dim FolderPath As String
Dim TempFile
Dim CurrentWB As Workbook
Dim CurrentWBSht As Worksheet
Dim CurrentShtLstRw As Long
Dim CurrentShtRowRef As Long
Dim CopyRange As Range
Dim ProjectNumber As String
FolderPath = "C:\test\"
TempFile = Dir(FolderPath)
Dim WkBk As Workbook
Dim WkBkIsOpen As Boolean
'Check is zmaster is open already
For Each WkBk In Workbooks
If WkBk.Name = "zmaster.xlsx" Then WkBkIsOpen = True
Next WkBk
If WkBkIsOpen Then
Set MasterWB = Workbooks("zmaster.xlsx")
Set MasterSht = MasterWB.Sheets("Blad1")
Else
Set MasterWB = Workbooks.Open(FolderPath & "zmaster.xlsx")
Set MasterSht = MasterWB.Sheets("Blad1")
End If
ProjectNumber = MasterSht.Cells(1, 1).Value
Do While Len(TempFile) > 0
'Checking that the file is not the master and that it is a xlsx
If Not TempFile = "zmaster.xlsx" And InStr(1, TempFile, "xlsx", vbTextCompare) Then
Set CopyRange = Nothing
'Note this is the last used Row, next empty row will be this plus 1
With MasterSht
MasterWBShtLstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set CurrentWB = Workbooks.Open(FolderPath & TempFile)
Set CurrentWBSht = CurrentWB.Sheets("Sheet1")
With CurrentWBSht
CurrentShtLstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
For CurrentShtRowRef = 1 To CurrentShtLstRw
If CurrentWBSht.Cells(CurrentShtRowRef, "A").Value = ProjectNumber Then
'This is set to copy from Column A to Column L as per the question
If CopyRange Is Nothing Then
'If there is nothing in Copy range then union wont work
'so first row of the work sheet needs to set the initial copyrange
Set CopyRange = CurrentWBSht.Range("A" & CurrentShtRowRef & _
":L" & CurrentShtRowRef)
Else
'Union is quicker to be able to copy from the sheet once
Set CopyRange = Union(CopyRange, _
CurrentWBSht.Range("A" & CurrentShtRowRef & _
":L" & CurrentShtRowRef))
End If ' ending If CopyRange Is Nothing ....
End If ' ending If CurrentWBSht.Cells....
Next CurrentShtRowRef
CopyRange.Select
'add 1 to the master file last row to be the next open row
CopyRange.Copy MasterSht.Cells(MasterWBShtLstRw + 1, 1)
CurrentWB.Close savechanges:=False
End If 'ending If Not TempFile = "zmaster.xlsx" And ....
TempFile = Dir
Loop
End Sub

Related

Save workbook as CSV with UTF-8 encoding

How can I save my workbook as CSV without losing UTF-8 characters?
So far, this the my code of saving workbook as CSV:
Option Explicit
Public wb As Workbook, ws As Worksheet, venture As String, intl As String, SvPath As String
Private Function chopFilesThenSave()
Dim NumOfColumns As Long
Dim RangeToCopy As Range
Dim RangeOfHeader As Range 'data (range) of header row
Dim WorkbookCounter As Integer
Dim RowsInFile 'how many rows (incl. header) in new files?
Dim p As Long
'Initialize data
Set ws = ThisWorkbook.Sheets("MixedNuts")
NumOfColumns = ws.UsedRange.Columns.Count
WorkbookCounter = 1
RowsInFile = 2000 + 1 'how many rows (incl. header in new files?
'Check if the folder provided is exist, else create one!
If Len(Dir(SvPath & "batch\", vbDirectory)) = 0 Then
MkDir SvPath & "batch\"
End If
'Copy the data of the first row (header)
Set RangeOfHeader = ws.Range(ws.Cells(1, 1), ws.Cells(1, NumOfColumns))
For p = 2 To ThisWorkbook.Sheets("Mixed").UsedRange.Rows.Count Step RowsInFile - 1
Set wb = Workbooks.Add
'Paste the header row in new file
RangeOfHeader.Copy wb.Sheets(1).Range("A1")
wb.Sheets(1).Range("A:B").NumberFormat = "#" 'set column as text
'Paste the chunk of rows for this file
Set RangeToCopy = ws.Range(ws.Cells(p, 1), ws.Cells(p + RowsInFile - 2, NumOfColumns))
RangeToCopy.Copy
wb.Sheets(1).Range("A2").PasteSpecial xlPasteValues
'Save the new workbook, and close it
wb.SaveAs SvPath & "batch\" & venture & intl & "BatchUpdate_" & Format(Now, "mmDDYYYY") & "-" & WorkbookCounter & ".csv", xlCSV
wb.Close False
'Increment file counter
WorkbookCounter = WorkbookCounter + 1
Next p
Set wb = Nothing
End Function
The code runs in a loop where I cut 2,000 rows (excluding headers) from sheet "MixedNuts", copy and paste to a new workbook then save it as CSV and do this again on the next row. But again, the problem is after saving it as CSV, utf-8 characters became question marks.

VBA loop throught cells and extract the file name from cells in excel sheet

I have an excel sheet that in each cell in column A , the path of a source folder :
column A
P:\Desktop\Source\Test1-folder\file1.txt
P:\Desktop\Source\Test1-folder\file2.txt
and i want to take just the file name (file1.txt) for each file , how can i do it ? Can you help me please ?
For Each oFolder In oSourceFolder.SubFolders
lastcol = Cells(1, Cells.Columns.Count).End(xlToLeft).Column
For Each oFile In oFolder.Files
If Dir(destinationFolder, 16) = "" Then MkDir (destinationFolder)
For k = 1 To dercol
numrows = worksh.Cells(Rows.Count, icol).End(xlUp).Row
For w = 2 To numrows
filepath = worksh.Cells(w, icol).Value
But this one loops through the files, not the cells. How can I loop through the cells?
Try this:
' Get the sheet
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(1)
' How you will slash it
Dim strSlash As String
strSlash = "\"
' Set the range for your tool
Dim rngFiles As Range
Dim rngCell As Range
Dim lngMaxRow As Long
lngMaxRow = Range("A" & Rows.Count).End(xlUp).Row
Set rngFiles = Range("A1:A" & lngMaxRow)
' Grab it from the rear
For Each rngCell In rngFiles.Cells
Debug.Print Right(rngCell.Value, Len(rngCell.Value) - InStrRev(rngCell.Value, strSlash))
Next
If all you want is the file name, you can do this with a simple worksheet formula:
=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",99)),99))

Create a summary sheet based on multiple worksheets

I have number of worksheets containing the same structure and same number of rows. Now I would like to create a master sheet to have an overview of all the worksheets using VBA.
It is like a balance sheet showing the performance over several years, which Years are on the headings and items are on rows.
Now the yearly data are put on multiple worksheets named "2012", "2013" and "2014".
Column B on sheet 1 ("2012") will be copied onto col B on "master" but for the following sheets ("2013", "2014"), data will be placed onto the next column on "master" (ie 2013 data on col C, 2014 data on col D).
I would like to have a workable macro which can count numbers of worksheets and copy paste specific data on a right column of master sheet.
1) create in a sheet a table like that: where the first column is where the destination cell in your Master report. And the 2nd column is where the data will be copied.
2) Put all your Worksheets in a folder
3) Run this macro, which need to be placed in Master module
Option Explicit
'assuming that:
'- "Excel Column Code" is in column A
'- "Form Cell Code" is in column B
'in zmaster.xlsm!Sheet2
Sub UpdateData()
Dim sFile As String, sPath As String
Dim srcWbk As Workbook, dstWbk As Workbook
Dim srcWsh As Worksheet, dstWsh As Worksheet, infoWsh As Worksheet
Dim i As Long, j As Long, k As Long
On Error GoTo Err_UpdateData
Set dstWbk = ThisWorkbook
Set dstWsh = dstWbk.Worksheets("Sheet1")
Set infoWsh = dstWbk.Worksheets("Sheet2")
sPath = "C:\Desktop\New folder\"
sFile = Dir(sPath)
Do While Len(sFile) > 0
If sFile = "zmaster.xlsm" Then
GoTo SkipNext
End If
Set srcWbk = Workbooks.Open(sPath & sFile)
Set srcWsh = srcWbk.Worksheets(1)
i = 2
'loop through the information about copy-paste method
Do While infoWsh.Range("A" & i) <> ""
'get first empty row, use "Excel Column Code" to get column name
j = GetFirstEmpty(dstWsh, infoWsh.Range("A" & i))
'copy data from source sheet to the destination sheet
'use "Form Cell Code" to define destination cell
srcWsh.Range(infoWsh.Range("B" & i)).Copy dstWsh.Range(infoWsh.Range("A" & i) & j)
i = i + 1
Loop
srcwbk.Close SaveChanges:=False
SkipNext:
sFile = Dir
Loop
Exit_UpdateData:
On Error Resume Next
Set srcWsh = Nothing
Set dstWsh = Nothing
Set srcWbk = Nothing
Set dstWbk = Nothing
Exit Sub
Err_UpdateData:
MsgBox Err.Description, vbExclamation, Err.Number
Resume Exit_UpdateData
End Sub
'returns first empty row in a destination sheet based on column name
Function GetFirstEmpty(ByVal wsh As Worksheet, Optional ByVal sCol As String = "A") As Long
GetFirstEmpty = wsh.Range(sCol & wsh.Rows.Count).End(xlUp).Row + 1
End Function

Excel VBA, Paste special adds trailing zeroes

I have raw data from ANSYS mechanical exported as .xml with the following format (2 rows, x number of columns):
Steps Time [s] [A] C1 (Total) [N]
1 1 1, 4,4163e+005
I have a lot of files and I'm trying to combine these into one table in Excel using VBA. The script works fine with one exception, it does not interpret the scientific format correctly. My result is as follows:
Steps 1
Time [s] 1
[A] C1 (Total) [N] 4,42E+09
Code looks as follows:
Private Sub CommandButton1_Click()
Dim directory As String, fileName As String, sheet As Worksheet, total As Integer
Dim wb1 As Excel.Workbook
Dim wb2 As Excel.Workbook
Set wb1 = ThisWorkbook
wb1.Sheets("Sheet1").Cells.ClearContents
'define table headers on row 1
wb1.Sheets("Sheet1").Range("A1:A1").Value = "Load Case"
wb1.Sheets("Sheet1").Range("B1:B1").Value = "Load Case"
wb1.Sheets("Sheet1").Range("C1:C1").Value = "Load Case"
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'directory of source files
directory = "C:\Users\xxxxxxx\Ansysxls\"
fileName = Dir(directory & "*.xl??")
'Define the last used row in the target sheet
LastRow = wb1.Sheets("Sheet1").Cells(wb1.Sheets("Sheet1").Rows.Count, "B").End(xlUp).Row + 1
Do While fileName = "Asymmetric.xls"
'define which workbook to open
Set wb2 = Workbooks.Open(directory & fileName)
'loop through sheets in source file
For Each sheet In Workbooks(fileName).Worksheets
'Select range in source file
wb2.Sheets(sheet.Name).Range("A1").CurrentRegion.Select
'Replace commas with dot
Selection.Replace What:=",", Replacement:=".", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False
Selection.Copy
'Paste Special to target file <-----Smth wrong in my paste special???
wb1.Sheets("Sheet1").Range("B" & LastRow).PasteSpecial _
Paste:=xlPasteValuesAndNumberFormats, SkipBlanks:=True, Transpose:=True
wb2.Sheets(sheet.Name).Activate
Next sheet
'define first row and last row of last import and add from what file the came
FirstRow = LastRow
LastRow = wb1.Sheets("Sheet1").Cells(wb1.Sheets("Sheet1").Rows.Count, "B").End(xlUp).Row + 1
'remove file ending ".xls" from column
wb1.Sheets("Sheet1").Range("A" & FirstRow & ":" & "A" & LastRow).Value = Left(fileName, Len(fileName) - 4)
Workbooks(fileName).Close
fileName = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
'Create Table
wb1.Sheets("Sheet1").ListObjects.Add(xlSrcRange, Sheets("Sheet1").Range("A1").CurrentRegion, , xlYes, Header = xlYes).Name = "myTable1"
End Sub
Can anybody help me understand why it changes with from e+5 to e+9?
Excel will 'interpret' the Total [N]) value (which has the comma in it) depending on the numbering system of your Excel application.
I believe if you paste a value of 4,4163e+005 into your worksheet, you will see a value of 4416300000, assuming your thousands are comma separated. In your case, however, you seem to want to convert the comma to a decimal point so that the true value is 441630. This can only be done if the value is a string, but yours probably isn't, it's most likely a number. I'm afraid I rather suspect your search and replace line makes no changes at all.
Although I can't see the values themselves, my bet would be that you need to divide each value by 10000 and then set the number format of your cells to "0.0000E+00".
I've put some code below that will loop through the values and make that change for you. You'll see that I've assumed each sheet only contains the 2 x 4 cell size, so adjust this if you need to.
Other comments about your code:
I think you need to put your last row update within the sheet loop. At a quick glance it looks as though you might be overwriting previous sheet data (ie the only data being written to your target is the source's last sheet data).
I'm not sure what you're intentions are with the Dir() function and then checking for a unique filename. It looks to me as if that will only loop once on a file called "Asymmetric.xls". If this is what you want then just define that workbook as an object. If you want to read all the workbooks in the directory then you need to run the Dir() loop until filename = "". That's what I've assumed in my code.
Private Sub CommandButton1_Click()
Dim directory As String
Dim fileName As String
Dim source As Workbook
Dim sht As Worksheet
Dim targetRng As Range
Dim rawValues As Variant
Dim revisedValues() As Variant
Dim rDimension As Long
Dim cDimension As Integer
Dim r As Long
Dim c As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'define table headers on row 1
With ThisWorkbook.Sheets("Sheet1")
.Cells.ClearContents
.Cells(1, 1).Resize(, 3).Value = _
Array("Filename", "Item", "Value")
Set targetRng = .Cells(2, 2) 'ie "B2"
End With
'Directory of source files
directory = "C:\Users\xxxxxxx\Ansysxls\"
fileName = Dir(directory & "*.xl??")
Do Until fileName = ""
'define which workbook to open
Set source = Workbooks.Open(directory & fileName)
'loop through sheets in source file
For Each sht In source.Worksheets
'Select range in source file
If Not IsEmpty(sht.Range("A1")) Then
rawValues = sht.Range("A1").CurrentRegion.Value2
' Manipulate the acquired data
rDimension = UBound(rawValues, 1)
cDimension = UBound(rawValues, 2)
' Transpose the dimensions and manipulate the totalN value
ReDim revisedValues(1 To cDimension, 1 To rDimension)
For r = 1 To rDimension
For c = 1 To cDimension
If r = 2 And c = 4 Then ' it's totalN
' Convert the data to a LongLong and divide by 10000
revisedValues(c, r) = CLngLng(rawValues(r, c)) / 10000
Else
revisedValues(c, r) = rawValues(r, c)
End If
Next
Next
'Populate the target sheet with revised values
Set targetRng = targetRng.Resize(cDimension, rDimension)
targetRng.Value2 = revisedValues
' Define the scientific format
targetRng.Cells(4, 2).NumberFormat = "0.0000E+00"
' Add the filename to column "A"
targetRng.Offset(, -1).Resize(, 1).Value2 = _
Left(fileName, (InStrRev(fileName, ".", -1, vbTextCompare) - 1))
' Move the targetRng to the bottom of this range
Set targetRng = targetRng.Offset(targetRng.Rows.Count)
End If
Next
source.Close
fileName = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

How to count number of rows in workbooks from sub folders in VBA?

I'm trying to count number of rows into files from some folders and sub folders. Folders and sub folders paths are written in a G column.
Sub CountRows()
Dim wbSource As Workbook, wbDest As Workbook
Dim wsSource As Worksheet, wsDest As Worksheet
Dim strFolder As String, strFile As String
Dim lngNextRow As Long, lngRowCount As Long
Dim LastRow
Dim cl As Range
Application.ScreenUpdating = False
Set wbDest = ActiveWorkbook
Set wsDest = wbDest.ActiveSheet
LastRow = wsDest.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
For Each cl In wsDest.Range("G11:G" & LastRow)
strFolder = cl.Value
strFile = Dir(strFolder & "/")
lngNextRow = 11
Do While Len(strFile) > 0
Set wbSource = Workbooks.Open(Filename:=strFolder & "/" & strFile)
Set wsSource = wbSource.Worksheets(1)
lngRowCount = wsSource.UsedRange.Rows.Count
wsDest.Cells(lngNextRow, "F").Value = lngRowCount - 1
wbSource.Close savechanges:=False
lngNextRow = lngNextRow + 1
strFile = Dir
Loop
Next cl
...
The result must be inserted in a column F. Maybe some one could explain, please, what is wrong with this loop, because count of rows in each file repeats in column F by number of directories.
For example, if I have 1 folder with 3 files, in column G I will have 3 directories ( 1 directory for each from 3 files C:\Users\Desktop\vba_files\ etc.), then I will get 3 numbers in column F that are a count of rows in each workbook from folder C:\Users\Desktop\vba_files\, but each count repeated 3 times (by number of directories).
It looks in a following way:
There is a problem with the logic in the code. You start off with column G containing an entry for every file, so for a folder with 3 files there are 3 repeated rows. But the Do While loop returns a length for every file in the current directory (since you keep calling Dir with no arguments). Then the For Each loop moves on to the next cell in column G, which contains the same directory again, the Do While loop starts again, and you get another 3 entries in column F.
I'm not sure why you would want to start with column G having those repeats, but if you do then you only need a single loop that runs down each cell in column G, and checks whether the directory has changed each time. The code below does this:
Sub CountRows()
Dim wbSource As Workbook, wbDest As Workbook
Dim wsSource As Worksheet, wsDest As Worksheet
Dim strFolder As String, strFile As String
Dim lngNextRow As Long, lngRowCount As Long
Dim LastRow
Dim cl As Range
'Application.ScreenUpdating = False
Set wbDest = ActiveWorkbook
Set wsDest = wbDest.ActiveSheet
LastRow = wsDest.Cells(wsDest.rows.count,7).end(xlUp).Row
lngNextRow = 11
strFolder = ""
For Each cl In wsDest.Range("G11:G" & LastRow)
If cl.Value <> strFolder Then
strFolder = cl.Value
strFile = Dir(strFolder & "/*.xl*")
Else
strFile = Dir
End If
If Len(strFile) > 0 Then
Set wbSource = Workbooks.Open(Filename:=strFolder & "/" & strFile)
Set wsSource = wbSource.Worksheets(1)
lngRowCount = wsSource.UsedRange.Rows.Count
wsDest.Cells(lngNextRow, "F").Value = lngRowCount - 1
wbSource.Close savechanges:=False
lngNextRow = lngNextRow + 1
End If
Next cl
End Sub
Note that if the number of files in the directory is greater than the number of corresponding entries in column G then the extra files will be ignored.
I added a filter to the first call to Dir() to pick up only Excel files. I also changed the way LastRow is calculated to a slightly safer way (your code would give wrong results if there was any data below and to the right of the last cell in G).
A neater way of achieving something like this is probably:
have the input just a list of directories with no duplication
loop through the input
for each input cell, output all files and counts on a separate output sheet
then you can pick up however many files are in each folder without having to get the number of entries in column G right.