Excel VBA, Paste special adds trailing zeroes - vba

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

Related

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

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

VLOOKUP to compare data in 2 different workbooks with VBA

I am somewhat new to VBA/Excel, so I was wondering if someone would help me out.
My question:
I have two different workbooks but in these workbooks two of the columns have common data. Thus I wanted to use VLOOKUP to compare the two columns and see if there are common data.
Details:
1st workbook : has 3 different sheets, I only need to use the sheet "Items" which has the data in column 2.
2nd workbook: has only 1 sheet called "Data" and has data in column 4.
Thus my goal is to compare the 2 columns. In workbook1 there is an empty column next to the data column so, if there is a match I want to say "ok" in it. If no match then "".
I tried VLOOKUP but really could not understand it. Plus this is for work.
You may try this..
Assuming the name of your second workbook is Book2.xlsx, then try this...
On First workbook
In C2
=IF(ISNUMBER(MATCH(B2,'[Book2.xlsx]Data'!$D:$D,0)),"OK","")
and copy it down.
If you require a VBA solution, one approach to get the desired output is as below...
The following code assumes that both the Book1.xlsm (which will contain the below code) and Book2.xlsx are saved in the same folder.
If they are saved at different location, change the path and name of Book2.xlsx in the following lines of code.
sourceFilePath = dwb.Path & "\"
sourceFileName = "Book2.xlsx"
Code:
Sub CompareData()
Dim swb As Workbook, dwb As Workbook
Dim sws As Worksheet, dws As Worksheet
Dim slr As Long, dlr As Long, i As Long
Dim sourceFilePath As String, sourceFileName As String
Dim x, y, z, dict
Application.ScreenUpdating = False
Set dwb = ThisWorkbook
Set dws = dwb.Sheets("Items")
dlr = dws.Cells(Rows.Count, 2).End(xlUp).Row
x = dws.Range("B2:B" & dlr).Value
ReDim z(1 To dlr)
sourceFilePath = dwb.Path & "\"
sourceFileName = "Book2.xlsx"
Workbooks.Open sourceFilePath & sourceFileName
Set swb = ActiveWorkbook
Set sws = swb.Sheets("Data")
slr = sws.Cells(Rows.Count, 4).End(xlUp).Row
y = sws.Range("D2:D" & slr).Value
Set dict = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(y, 1)
dict.Item(y(i, 1)) = ""
Next i
swb.Close False
For i = 1 To UBound(x, 1)
If dict.exists(x(i, 1)) Then
z(i) = "OK"
Else
z(i) = ""
End If
Next i
dws.Range("C2").Resize(UBound(x, 1), 1).Value = Application.Transpose(z)
Application.ScreenUpdating = True
End Sub

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.

Comparing column cell contents to a text file and copying matching rows to another workbook VBA

I have no idea what I am doing and if you feel like yelling at me that's cool.
I am wondering how I would go about checking values of each cell in column D on a worksheet called PriceList against values in a text file ItemNumber.txt.
If the content of the cells in the column is equal to one of the values in said text file I want it to copy the row and paste it into sheet1....
Option Explicit
Sub CompareValue()
Dim FileNum As Integer
Dim DataLine As String
Dim cel As Range
Dim celString As String
' Select file to be opened
FileNum = FreeFile()
Open "C:\Users\jreinhold\Documents\ItemNumbers.txt" For Input As #FileNum
Set myRange = Range("D:D")
For i = 1 To myRange.Rows.Count 'loop through rows by using i as a cell reference
Do While Not EOF(FileNum) 'run input from file while not end of file
Line Input #FileNum, DataLine 'input line data into DataLine
' Check value of cell against read in data
If InStr(DataLine, myRange.Cells("D", i).Value) = 0 Then 'compare DataLine to cell i
' Copy Row Where match resides
DataLine = DataLine + 1 'if value of comparison is 0 add 1 to data line and get next line in text file
Loop 'Loop back around and plus next line for the data from the file in and check values against cell i again
End If 'end If once value for comparison is true
Source.Rows(c.Row).Copy Target.Rows(i) ' Copy row
Sheets("Sheet1").Paste ' Paste row into Sheet1
i = i + 1 ' add 1 to i in order to continue to next cell in column
Next i 'check next cell for the data inputs using the same code.
Wend
End Sub
Try this:
Sub CompareValue()
Dim mainWS As Worksheet, dataWS As Worksheet, txtWS As Worksheet
Dim FileNum&, i&, j&
Dim DataLine As String, celString$
Dim cel As Range, myRange As Range
Dim ranOnce As Boolean
ranOnce = False ' Check if we've added a line to your new sheet
Dim fileName$, filePath$, fullFile$
filePath = "C:\Users\bWayne\"
fileName = "myTextDoc.txt"
fullFile = filePath & fileName
Set dataWS = Sheets("Data") ' Rename this, this sheet has your column D with the values to check
Set mainWS = Sheets("Sheet1") ' This is where the row from DATA will be copied to, if a match is found in the text file.
' This will call a sub that will put the text into the temp sheet
TextFile_PullData fullFile, mainWS
Set txtWS = Sheets(Left(fileName, WorksheetFunction.Search(".", fileName) - 1))
' Now we have the text file informaiton in a sheet. So just loop through the cells in "Data" and check if there's a match in the text
Dim lastRow&
lastRow = dataWS.Cells(dataWS.Rows.Count, 4).End(xlUp).Row
Set myRange = dataWS.Range("D1:D" & lastRow) ' edit this as necessary
For Each cel In myRange
If WorksheetFunction.CountIf(txtWS.Range("A1:A" & txtWS.UsedRange.Rows.Count), cel.Value) > 0 Then
' Since we found a match, copy the entire row to "Sheet1"
Dim newLastRow&
newLastRow = mainWS.Cells(mainWS.Rows.Count, 4).End(xlUp).Row
If ranOnce Then newLastRow = newLastRow + 1
ranOnce = True
mainWS.Rows(newLastRow).EntireRow.Value = cel.EntireRow.Value
End If
Next cel
End Sub
Sub TextFile_PullData(fileName As String, mySheet As Worksheet)
Workbooks.OpenText fileName:=fileName, _
Origin:=437, StartRow:=1, DataType:=xlDelimited, TextQualifier:= _
xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, _
Comma:=False, Space:=False, Other:=False, FieldInfo:=Array(1, 1), _
TrailingMinusNumbers:=True
ActiveSheet.Copy after:=mySheet
End Sub
Instead of going line by line, I just imported the Text file into Excel, and am just doing a CountIf() to see if there's a match. If so, copy that row to your new sheet. Please note you will probably want to change the Sheets, as it's not clear to me where you want the data to go. This should help get you going though! I recommend stepping through with F8 just to make sure it works.
Edit: You had some loops in there that I may have not considered, so let me know if I'm missing something.

Export range with data to single CSV file

What is an efficient way to export a particular range of cells with data from Excel 2010 to CSV using VBA? The data always starts at cell A3. The end of the range depends on the dataset (always column Q but row end may vary). It should only export data from sheet 2 called 'Content' and the cells need to contain only 'real' data like text or numbers, not empty values with formulas.
The reason cells have formulas is because they reference cells from sheet 1 and 3. Formulas use normal reference and also vertical searches.
Using the UsedRange will export all the cells which are used by Excel. This works, but it also ends up exporting all the empty cells containing formulas but no data leading to lots (510 to be precise) of unnecessary semicolons in the output .csv.
Sub SavetoCSV()
Dim Fname As String
Sheets("Content").UsedRange.Select
Selection.Copy
Fname = "C:\Test\test.csv"
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs Filename:=Fname, _
FileFormat:=xlCSV, CreateBackup:=False, local:=True
Application.DisplayAlerts = False
ActiveWorkbook.Close
Application.DisplayAlerts = True
End Sub
One solution might be to change the UsedRange in the VB code with Offset or Resize. Another might be to create a RealRange variable and then selectcopy that.
Similar kind of questions have been asked more than once, like here, here and here, and I've also looked at SpecialCells, but somehow I cannot get it to work the way I want it to.
I have tried the below code, but it ends up adding rows from sheet 3 as well.
Sub ExportToCSV()
Dim Fname As String
Dim RealRange As String
Dim Startrow As Integer
Dim Lastrow As Integer
Dim RowNr As Integer
Startrow = 3
RowNr = Worksheets("Content").Cells(1, 1).Value 'this cells has a MAX function returning highest row nr
Lastrow = RowNr + 3
RealRange = "A" & Startrow & ":" & "Q" & Lastrow
Sheets("Content").Range(RealRange).Select
Selection.Copy
Fname = "C:\Test\test.csv"
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs Filename:=Fname, _
FileFormat:=xlCSV, CreateBackup:=False, local:=True
Application.DisplayAlerts = False
'ActiveWorkbook.Close
Application.DisplayAlerts = True
End Sub
If I'm looking in the wrong direction, please refer to other options.
If I understand, you only want to export the cell if it has a value in it. This is going to lead to a csv with different numbers of columns in it. If that's truly what you are trying to do then the fastest way I think is writing your results to a file as below. This ran in about 1 second for 20,000 rows
Dim Lastrow As Integer
Dim RowNr As Integer
Dim SourceSheet As Worksheet
Const Fname As String = "C:\Test\test.csv"
Const StartRow As Integer = 3
Sub ExportToCSV()
On Error GoTo errorhandler
Set SourceSheet = Worksheets("Content")
TargetFileNumber = FreeFile()
Open Fname For Output As #TargetFileNumber 'create the file for writing
Lastrow = SourceSheet.Cells(1, 1).Value + 3 'I would just use the used range to count the rows but whatever
For r = StartRow To Lastrow 'set up two loops to go through the rows column by column
Line = ""
If SourceSheet.Cells(r, 1).Value <> "" Then 'check if there is a value in the cell, if so export whole row
For c = 1 To 17 'Columns A through Q
Line = Line & SourceSheet.Cells(r, c).Value & "," 'build the line
Next c
Line = Left(Line, Len(Line) - 1) 'strip off last comma
Print #TargetFileNumber, Line 'write the line to the file
End If
Next r
GoTo cleanup
errorhandler:
MsgBox Err.Number & " --> " & Err.Description, vbCritical, "There was a problem!"
cleanup:
Close #TargetFileNumber
End Sub