Comparing column cell contents to a text file and copying matching rows to another workbook VBA - 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.

Related

How to combine workbooks from their actual start values (no appending)

I’m really sorry if this is a silly question but the macro I’m currently using keeps appending the new workbooks data when I’m combining them.
Ideally, I want the new workbook to be beside it at cells AA1 instead of directly appending like it is in the picture. I’m sorry I can’t be much more help. I’ve been going through it trying to get it to start for the other workbooks to not append but write where it actually is from the other workbooks. No luck so far.
I’m sure I’ll get there in a few hours or so, but thanks again if you’re willing to assist.
Option Explicit
Public Sub CombineManyWorkbooksIntoOneWorksheet()
Dim strDirContainingFiles As String, strFile As String, _
strFilePath As String
Dim wbkDst As Workbook, wbkSrc As Workbook
Dim wksDst As Worksheet, wksSrc As Worksheet
Dim lngIdx As Long, lngSrcLastRow As Long, _
lngSrcLastCol As Long, lngDstLastRow As Long, _
lngDstLastCol As Long, lngDstFirstFileRow As Long
Dim rngSrc As Range, rngDst As Range, rngFile As Range
Dim colFileNames As Collection
Set colFileNames = New Collection
'Set references up-front
strDirContainingFiles = "C:\Users\Guide\Projects\" '<~ your folder
Set wbkDst = Workbooks.Add '<~ Dst is short for destination
Set wksDst = wbkDst.ActiveSheet
'Store all of the file names in a collection
strFile = Dir(strDirContainingFiles & "\*.xlsm")
Do While Len(strFile) > 0
colFileNames.Add Item:=strFile
strFile = Dir
Loop
''CHECKPOINT: make sure colFileNames has the file names
'Dim varDebug As Variant
'For Each varDebug In colFileNames
' Debug.Print varDebug
'Next varDebug
'Now we can start looping through the "source" files
'and copy their data to our destination sheet
For lngIdx = 1 To colFileNames.Count
'Assign the file path
strFilePath = strDirContainingFiles & "\" & colFileNames(lngIdx)
'Open the workbook and store a reference to the data sheet
Set wbkSrc = Workbooks.Open(strFilePath)
Set wksSrc = wbkSrc.Worksheets("Sheet1")
'Identify the last row and last column, then
'use that info to identify the full data range
lngSrcLastRow = LastOccupiedRowNum(wksSrc)
lngSrcLastCol = LastOccupiedColNum(wksSrc)
With wksSrc
Set rngSrc = .Range(.Cells(1, 1), .Cells(lngSrcLastRow, _
lngSrcLastCol))
End With
''CHECKPOINT: make sure we have the full source data range
'wksSrc.Range("A1").Select
'rngSrc.Select
'If this is the first (1st) loop, we want to keep
'the header row from the source data, but if not then
'we want to remove it
If lngIdx <> 1 Then
Set rngSrc = rngSrc.Offset(1, 0).Resize(rngSrc.Rows.Count - 1)
End If
''CHECKPOINT: make sure that we remove the header row
''from the source range on every loop that is not
''the first one
'wksSrc.Range("A1").Select
'rngSrc.Select
'Copy the source data to the destination sheet, aiming
'for cell A1 on the first loop then one past the
'last-occupied row in column A on each following loop
If lngIdx = 1 Then
lngDstLastRow = 1
Set rngDst = wksDst.Cells(1, 1)
Else
lngDstLastRow = LastOccupiedRowNum(wksDst)
Set rngDst = wksDst.Cells(lngDstLastRow + 1, 1)
End If
rngSrc.Copy Destination:=rngDst '<~ this is the copy / paste
'Almost done! We want to add the source file info
'for each of the data blocks to our destination
'On the first loop, we need to add a "Source Filename" column
If lngIdx = 1 Then
lngDstLastCol = LastOccupiedColNum(wksDst)
wksDst.Cells(1, lngDstLastCol + 1) = "Source Filename"
End If
'Identify the range that we need to write the source file
'info to, then write the info
With wksDst
'The first row we need to write the file info to
'is the same row where we did our initial paste to
'the destination file
lngDstFirstFileRow = lngDstLastRow + 1
'Then, we need to find the NEW last row on the destination
'sheet, which will be further down (since we pasted more
'data in)
lngDstLastRow = LastOccupiedRowNum(wksDst)
lngDstLastCol = LastOccupiedColNum(wksDst)
'With the info from above, we can create the range
Set rngFile = .Range(.Cells(lngDstFirstFileRow, lngDstLastCol), _
.Cells(lngDstLastRow, lngDstLastCol))
''CHECKPOINT: make sure we have correctly identified
''the range where our file names will go
'wksDst.Range("A1").Select
'rngFile.Select
'Now that we have that range identified,
'we write the file name
rngFile.Value = wbkSrc.Name
End With
'Close the source workbook and repeat
wbkSrc.Close SaveChanges:=False
Next lngIdx
'Let the user know that the combination is done!
''MsgBox "Data combined!"
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT : Sheet, the worksheet we'll search to find the last row
'OUTPUT : Long, the last occupied row
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedRowNum(Sheet As Worksheet) As Long
Dim lng As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
With Sheet
lng = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End With
Else
lng = 1
End If
LastOccupiedRowNum = lng
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT : Sheet, the worksheet we'll search to find the last column
'OUTPUT : Long, the last occupied column
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedColNum(Sheet As Worksheet) As Long
Dim lng As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
With Sheet
lng = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
End With
Else
lng = 1
End If
LastOccupiedColNum = lng
End Function
You should identify the individual tasks that you program will have to perform and create methods and functions to handle these smaller tasks. Doing this will allow you to easily debug your code.
get1stCellInNextColumn - Defines the Target range
getFileCollection - Collect all the file paths
getLastUsedCell - Gets the last used cell in a range. Used to define both Source and Target ranges
getSourceRange - Gets the Source Range
InsertData - Opens a Source file and copies its data to a Target Workbook
Main_CombineManyWorkbooksIntoOneWorksheet - Process all the files
Option Explicit
'This is the Main function that combines all the other Subs and Functions together to process the data
Public Sub Main_CombineManyWorkbooksIntoOneWorksheet()
Application.ScreenUpdating = False
Const FOLDERNAME As String = "C:\Users\best buy\Downloads\_Temp\" ' "C:\Users\Guide\"
Const EXTENSION As String = "\*.xlsx" '"\*.xlsm"
Dim cFiles As Collection
Dim x As Long
Set cFiles = getFileCollection(FOLDERNAME, EXTENSION)
With Workbooks.Add
For x = 1 To cFiles.Count
InsertData cFiles.Item(x), .Worksheets(1)
Next
End With
Application.ScreenUpdating = True
End Sub
'Opens Source Workbook, Copies Data to Target Worksheet and then closes the Source Workbook
Public Sub InsertData(SourceWBName As String, TargetWS As Worksheet)
Dim rSource As Range
With Workbooks.Open(SourceWBName)
Set rSource = getSourceRange(.Worksheets("Sheet1"))
If rSource Is Nothing Then
Debug.Print .FullName, "No Data Found"
Else
rSource.Copy get1stCellInNextColumn(TargetWS.UsedRange)
End If
.Close SaveChanges:=False
End With
End Sub
'Collects the full file paths for the Source workbooks
Function getFileCollection(FOLDERNAME As String, FileExtension As String) As Collection
Dim FileName As String
Dim col As Collection
Set col = New Collection
'Store all of the file names in a collection
FileName = Dir(FOLDERNAME & FileExtension)
Do While Len(FileName) > 0
col.Add Item:=FOLDERNAME & FileName
FileName = Dir
Loop
Set getFileCollection = col
End Function
'Gets the Source range from a Worksheet
Function getSourceRange(xlWS As Worksheet) As Range
Dim rLastCell As Range
With xlWS
Set rLastCell = getLastUsedCell(.UsedRange, True, True)
If Not rLastCell Is Nothing Then Set getSourceRange = .Range(.Cells(1, 1), rLastCell)
End With
End Function
'Gets the first cell in the next unused Column of the Target range
Function get1stCellInNextColumn(Target As Range) As Range
Dim r As Range
'Get last used cell in last used column of the Target range
Set r = getLastUsedCell(Target, False, True)
If r Is Nothing Then
Set r = Target.EntireColumn.Cells(1, 1)
Else
'Get the first cell in the next column adjacent to the Target range
Set r = Target.Columns(Target.Columns.Count).Next
End If
Set get1stCellInNextColumn = r
End Function
'Gets the last used cell the last used row
'Or the last used cell the last used column
'Or the last used cells in the Target range
Function getLastUsedCell(Target As Range, InRow As Boolean, InColumn As Boolean) As Range
Dim rRow As Range, rColumn As Range
If Target Is Nothing Then Exit Function
With Target
Set rRow = .Find(What:="*", After:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
If rRow Is Nothing Then Exit Function
Set rColumn = .Find(What:="*", After:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
If InRow And InColumn Then 'Get last used cell in last used column
Set getLastUsedCell = Intersect(rRow.EntireRow, rColumn.EntireColumn)
ElseIf InRow Then 'Get last used cell in last used row
Set getLastUsedCell = rRow
ElseIf InColumn Then 'Get last used cell in last used column
Set getLastUsedCell = rColumn
End If
End With
End Function
Sorry to answer my own question but I figured it out after a bit of debugging. The following code below does not append and creates the excels exactly as you need them. Change the values as you see fit or use original code if you need to append.
Option Explicit
Public Sub CombineManyWorkbooksIntoOneWorksheet()
Dim strDirContainingFiles As String, strFile As String, _
strFilePath As String
Dim wbkDst As Workbook, wbkSrc As Workbook
Dim wksDst As Worksheet, wksSrc As Worksheet
Dim lngIdx As Long, lngSrcLastRow As Long, _
lngSrcLastCol As Long, lngDstLastRow As Long, _
lngDstLastCol As Long, lngDstFirstFileRow As Long
Dim rngSrc As Range, rngDst As Range, rngFile As Range
Dim colFileNames As Collection
Set colFileNames = New Collection
'Set references up-front
strDirContainingFiles = "C:\Users\Guide\" '<~ your folder
Set wbkDst = Workbooks.Add '<~ Dst is short for destination
Set wksDst = wbkDst.ActiveSheet
'Store all of the file names in a collection
strFile = Dir(strDirContainingFiles & "\*.xlsm")
Do While Len(strFile) > 0
colFileNames.Add Item:=strFile
strFile = Dir
Loop
''CHECKPOINT: make sure colFileNames has the file names
'Dim varDebug As Variant
'For Each varDebug In colFileNames
' Debug.Print varDebug
'Next varDebug
'Now we can start looping through the "source" files
'and copy their data to our destination sheet
For lngIdx = 1 To colFileNames.Count
'Assign the file path
strFilePath = strDirContainingFiles & "\" & colFileNames(lngIdx)
'Open the workbook and store a reference to the data sheet
Set wbkSrc = Workbooks.Open(strFilePath)
Set wksSrc = wbkSrc.Worksheets("Sheet1")
'Identify the last row and last column, then
'use that info to identify the full data range
lngSrcLastRow = LastOccupiedRowNum(wksSrc)
lngSrcLastCol = LastOccupiedColNum(wksSrc)
With wksSrc
Set rngSrc = .Range(.Cells(1, 1), .Cells(lngSrcLastRow, _
lngSrcLastCol))
End With
''CHECKPOINT: make sure we have the full source data range
'wksSrc.Range("A1").Select
'rngSrc.Select
'If this is the first (1st) loop, we want to keep
'the header row from the source data, but if not then
'we want to remove it
''CHECKPOINT: make sure that we remove the header row
''from the source range on every loop that is not
''the first one
'wksSrc.Range("A1").Select
'rngSrc.Select
'Copy the source data to the destination sheet, aiming
'for cell A1 on the first loop then one past the
'last-occupied row in column A on each following loop
If lngIdx = 1 Then
lngDstLastRow = 1
Set rngDst = wksDst.Cells(1, 1)
Else
lngDstLastRow = 1
Set rngDst = wksDst.Cells(1, 20)
End If
rngSrc.Copy Destination:=rngDst '<~ this is the copy / paste
'Close the source workbook and repeat
wbkSrc.Close SaveChanges:=False
Next lngIdx
'Let the user know that the combination is done!
''MsgBox "Data combined!"
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT : Sheet, the worksheet we'll search to find the last row
'OUTPUT : Long, the last occupied row
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedRowNum(Sheet As Worksheet) As Long
Dim lng As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
With Sheet
lng = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End With
Else
lng = 1
End If
LastOccupiedRowNum = lng
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT : Sheet, the worksheet we'll search to find the last column
'OUTPUT : Long, the last occupied column
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedColNum(Sheet As Worksheet) As Long
Dim lng As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
With Sheet
lng = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
End With
Else
lng = 1
End If
LastOccupiedColNum = lng
End Function

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

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

Find row value, copy row and all the range underneath for data reduction

I am trying to use a macro to clean up data files and only copy on Sheet2 what is most relevant.
I have written the code to find the row I want the data to be copied from. However I can only copy the row itself and not the range underneath. Please note I need the range to go from that row to the last column and last row as the size of the matriz always varies.
s N s N s N s N s rpm
Linear Real Linear Real Linear Real Linear Real Linear Amplitude
0.0000030 9853.66 0.0000030 5951.83 0.0000030 533.48 0.0000030 476.15 0.0000030 2150.16
0.0000226 9848.63 0.0000226 5948.19 0.0000226 557.02 0.0000226 488.60 0.0000226 2150.16
0.0000421 9826.05 0.0000421 5956.22 0.0000421 615.94 0.0000421 480.75 0.0000421 2150.15
0.0000616 9829.72 0.0000616 5989.72 0.0000616 642.59 0.0000616 476.77 0.0000616 2150.15
So basically the code below finds that first row and copies it in Sheet2. I need the macro to also select the range underneath and copy it onto Sheet2. Please can you help me finishing off the script?
Sub SearchForRawData()
Dim LSearchRow As Integer
Dim LCopyToRow As Integer
On Error GoTo Err_Execute
'Start search in row 1
LSearchRow = 1
'Start copying data to row 2 in Sheet2 (row counter variable)
LCopyToRow = 2
While Len(Range("A" & CStr(LSearchRow)).Value) >= 0
'If value in column A = "s", copy entire row to Sheet2
If Range("A" & CStr(LSearchRow)).Value = "s" Then
'Select row and range in Sheet1 to copy
Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Select
Selection.Copy
'Paste row into Sheet2 in next row
Sheets("Sheet2").Select
Rows(CStr(LCopyToRow) & ":" & CStr(LCopyToRow)).Select
ActiveSheet.Paste
'Select all Raw Data underneath found Row to Copy
'Paste all Raw Data into Sheet 2
'Move counter to next row
LCopyToRow = LCopyToRow + 1
'Go back to Sheet1 to continue searching
Sheets("Sheet1").Select
End If
LSearchRow = LSearchRow + 1
Wend
'Position on cell A1
Application.CutCopyMode = False
Range("A1").Select
MsgBox "All matching data has been copied."
Exit Sub
Err_Execute:
MsgBox "An error has occured"
End Sub
You don't need a loop for this if you want to copy the row that has the "s" and everything below it to the target sheet. The following sub finds the row with the "s" in column A and then copies that row and everything below it to the target sheet.
Note that you should always avoid selecting or activating anything in VBA code, and that the normal way to copy and paste relies on selecting. If you use the syntax I've included here, the clipboard is not used and the target sheet does not need to be selected.
Sub CopyRowAndBelowToTarget()
Dim wb As Workbook
Dim src As Worksheet
Dim tgt As Worksheet
Dim match As Range
Set wb = ThisWorkbook
Set src = wb.Sheets("Sheet1")
Set tgt = wb.Sheets("Sheet2")
Dim lastCopyRow As Long
Dim lastPasteRow As Long
Dim lastCol As Long
Dim matchRow As Long
Dim findMe As String
' specify what we're searching for
findMe = "s"
' find our search string in column A (1)
Set match = src.Columns(1).Find(What:=findMe, After:=src.Cells(1, 1), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
' figure out what row our search string is on
matchRow = match.Row
' get the last row and column with data so we know how much to copy
lastCopyRow = src.Range("A" & src.Rows.Count).End(xlUp).Row
lastCol = src.Cells(1, src.Columns.Count).End(xlToLeft).Column
' find out where on our target sheet we should paste the results
lastPasteRow = tgt.Range("A" & src.Rows.Count).End(xlUp).Row
' use copy/paste syntax that doesn't use the clipboard
' and doesn't select or activate
src.Range(Cells(matchRow, 1), Cells(lastCopyRow, lastCol)).Copy _
tgt.Range("A" & lastPasteRow)
End Sub
Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Select
So firstly you don't acutally need the CStr, vba will cast numbers to strings by itself, i.e. Range(LSearchRow & ":" & LSearchRow) should work fine.
To find how many rows down to go use the end function of the range object:
bottomRow = Range("A" & LSearchRow).End(xldown).Row
Do the same for the column
lastCol = Range("A" & LSearchRow).End(xlleft).column
Now to copy:
Range("A" & LSearchRow & ":" & lastCol & bottomRow).Copy
However if you have empty cells inthe middleof the data then instead of using End(xldown), start at the bottom of the sheet and look up:
bottomRow = Range("A1000000").End(xlup).Row
etc

Excel 2003: Programmatic sort of sheet in different workbook

From the current workbook, I want to open a sheet in the source workbook, turn off any filtering that may be present, sort by one column, then another, then another. Am getting 1004 and other errors. This needs to run on 2003. Any help will be appreciated!
Dim WB As Workbook, WasWBOpen As Boolean, srcfile As String, srcpath As String,
onecol as integer, twocol as integer, thrcol as integer
srcpath = "blahblah"
srcfile = "blah.xls"
On Error Resume Next
Set WB = Workbooks(srcfile)
WasWBOpen = True
On Error GoTo 0
If WB Is Nothing Then
Set WB = Workbooks.Open(srcpath & srcfile, UpdateLinks:=False)
WasWBOpen = False
End If
'code before this opens source wkbook
lstrow = Worksheets("Sheet1").UsedRange.Row - 1 + Worksheets("Sheet1").UsedRange.Rows.Count
lstcol = Worksheets("Sheet1").UsedRange.Column - 1 + Worksheets("Sheet1").UsedRange.Columns.Count
onecol=3
twocol=5
thrcol=8
With WB.Sheets("Sheet1")
.AutoFilterMode = False
.Range("1:1").AutoFilter
'Here's where error occurs--
.Range(Cells(1, 1), Cells(lstrow, lstcol)).Sort _
Key1:=Columns(onecol), Order1:=xlAscending, _
Key2:=Columns(twocol), Order2:=xlAscending, _
Key3:=Columns(thrcol), Order3:=xlAscending, Header:=xlYes
End With
If WasWBOpen = False Then
WB.Close
End If
.Range(Cells(1, 1), Cells(lstrow, lstcol)).Sort _
is better written as:
.Range(.Cells(1, 1), .Cells(lstrow, lstcol)).Sort _
The only thing I can make a stab at is perhaps your selection does not include columns 3, 5 or 8. What are the values of lstrow and lstcol before the error?
In my experience you can only sort the active worksheet. Try adding .Activate after WB.Sheets("Sheet1").
Information about the last sort is stored against the worksheet. I sometimes suspect this is the problem rather than the sheet to be sorted not being active. But .Activate has always worked for me and so I have never investigated further.
Extra information
I had assumed it was the Sort that generated the error but it is the AutoFilter.
I can generate a 1004 error by leaving row 1 empty.
What purpose does the AutoFilter statement serve? With AutoFilterMode = False I would expect it to return Nothing. Why not delete this statement?
I am also concerned about the range you are sorting. You are subtracting the number of unused rows at the top and unused columns on the left to calculate lstrow and lstcol but then including those unused rows and columns in the sort. The result is that rows at the bottom and columns on the right would not be sorted.
If have not got any unused rows at the top and unused columns on the left, this will not matter but you need to decide which range you want to sort.
Extra information 2
This section was added after I discovered a fourth way of breaking the original code. The following code appears to be bomb-proof.
Option Explicit
Sub TestSort2()
Dim WB As Workbook, WasWBOpen As Boolean, srcfile As String, srcpath As String
Dim onecol As Integer, twocol As Integer, thrcol As Integer
' Undeclared or new variables
Dim InxWB As Long
Dim lstrow As Long
Dim lstcol As Long
Dim srcpathfile As String
' Report the name of the active workbook
Debug.Print "Original active workbook " & ActiveWorkbook.Name
' I created two workbooks named "Failed sort 1.xls" and "Failed sort 2.xls".
' Both are in the same directory. "Failed sort 1.xls" contains this macro.
' "Failed sort 2.xls" contains the data.
srcpath = Application.ActiveWorkbook.Path
srcfile = "Failed sort 2.xls"
srcpathfile = srcpath & "\" & srcfile
WasWBOpen = False
' Check the open workbook for srcfile
For InxWB = 1 To Workbooks.Count
If Workbooks(InxWB).Name = srcfile Then
' Required workbook already open
Set WB = Workbooks(InxWB)
WB.Activate ' Activate it
WasWBOpen = True
Exit For
End If
Next
If Not WasWBOpen Then
' Files was not open
If Dir(srcpathfile) <> "" Then
' File exists
' Do you need UpdateLinks:=False? If there are links
' with the sort be affected if they are not updated?
Set WB = Workbooks.Open(srcpathfile, UpdateLinks:=False)
Else
' File does not exist
Call MsgBox(srcpathfile & " does not exist", vbOKOnly)
Exit Sub
End If
End If
' WB is now the active workbook whether it was open before or not
Debug.Print "Final active workbook " & ActiveWorkbook.Name ' Confirm
With Sheets("Sheet1")
.Activate
.AutoFilterMode = False
' Get the last used row and cell of the worksheet
lstrow = Cells.SpecialCells(xlCellTypeLastCell).Row
lstcol = Cells.SpecialCells(xlCellTypeLastCell).Column
onecol = 3
twocol = 5
thrcol = 8
If onecol > lstcol Or twocol > lstcol Or thrcol > lstcol Then
Call MsgBox("The sort range does include the sort columns", vbOKOnly)
If Not WasWBOpen Then
Close
End If
Exit Sub
End If
Range(Cells(1, 1), Cells(lstrow, lstcol)).Sort _
Key1:=Columns(onecol), Order1:=xlAscending, _
Key2:=Columns(twocol), Order2:=xlAscending, _
Key3:=Columns(thrcol), Order3:=xlAscending, Header:=xlYes
End With
If Not WasWBOpen Then
Close
End If
End Sub