Optimize this Code (Vlookup-like code) - excel

I have 2 files. The first file, which will already be open when the user runs the macro has 5 worksheets. Each worksheet contains an "Order-Item" column in a different location. An example worksheet would look something like this
-Date Time Order-item Order-Quanity
-1020 9:30 item533333 (blank)
-1020 7:30 item733333 (blank)
-1020 2:30 item333332 (blank)
-1020 6:30 item121242 (blank)
After running the macro, the user will select a file to open that looks like this:
-Order-item Order-Quantity
-item121242 183
-item333332 515
-item533333 27
-item333332 761
The macro then goes through every worksheet from the original file. On each worksheet it finds where the order-item column is located then goes through each item on the column. It searches the user-selected file for the order-item (usually column A) and looks up the quantity(always adjacent to order-item column, in this case column B)
After running the original worksheet should look like this:
-Date Time Order-item Order-Quanity
-1020 9:30 item533333 27
-1020 7:30 item733333 515
-1020 2:30 item333332 761
-1020 6:30 item121242 183
I have created a macro that does this but as both files are rather large(the original file has about 10,000 rows and the user-opened file has upto 50,000 rows) my macro takes some time to execute. I realize I could simply do a Vlookup,filldown, then paste values and it would be much quicker; however this is part of a larger automation macro and this isn't feasible. Is there any improvements anyone could suggest to make my code run more efficent or quicker? If so let me know. Thanks!
Public Sub OpenFile()
Dim FilePath As Variant
Dim FileName As String
Dim CurrentWorkbook As String
Dim thisWB As Workbook
Dim openWB As Workbook
Dim sh As Worksheet
Dim lastRow As Long
Dim myRange As Range
Dim FoundCell As Range
Dim counter1 As Long
Dim counter2 As Long
Dim orderColumn As Long
Set thisWB = Application.ActiveWorkbook
CurrentWorkbook = Application.ActiveWorkbook.Name
FilePath = Application.GetOpenFilename(FileFilter:= _
"Excel Workbook Files(*.xl*),*.xl*", MultiSelect:=False, Title:="Select File")
If Not FilePath = False Then
FileName = FilePath
Set openWB = Application.Workbooks.Open(FileName)
FileName = Mid(FileName, InStrRev(FileName, "\") + 1, Len(FileName)) 'extracts filename from path+filename
Else
MsgBox ("File not selected or selected file not valid")
Exit Sub
End If
Application.Workbooks(FileName).Activate
'--------------------------------------------------------------------------------------------------
'--------------gets table range from input box. Defailt is Row A,B--------------------------------
'--------------------------------------------------------------------------------------------------
Set myRange = Application.InputBox( _
"Select Table Range. First Column should be Order-item, Second Column should be Order Grade", _
"Select Range", "$A:$B", , , , , 8)
On Error GoTo 0
'for every worksheet in currentworkbook, find how many rows there are.and find location of _
order-item. then go through each row in the order-item column and compare to column A(order-item) _
on the user selected workbook. if match is found, place column B into order-item column+1
Application.ScreenUpdating = False
For Each sh In thisWB.Worksheets
lastRow = LastRowUsed(sh)
'Find Order Column
Set FoundCell = sh.Rows(1).Find(what:="Order-Item", LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not FoundCell Is Nothing Then
orderColumn = FoundCell.Column
Else
MsgBox ("Couldn't find ""Order-Item"" in Header, exiting macro")
Exit Sub
End If
For counter1 = lastRow To 1 Step -1
For counter2 = myRange.Rows.Count To 1 Step -1
If sh.Cells(counter1, orderColumn) = myRange.Cells(counter2, 1).Value Then
sh.Cells(counter1, orderColumn + 1) = myRange.Cells(counter2, 2)
Exit For
End If
Next
Next
Next
Application.ScreenUpdating = True
End Sub

Why don't you make your VBA use Application.worksheetFunction.VLOOKUP ?

EDIT: updated to handle duplicate Id's.
Sub Tester()
UpdateFromSelection Workbooks("Book3").Sheets("Sheet1").Range("A1:B21")
End Sub
Sub UpdateFromSelection(myRange As Range)
Dim d, rw As Range, tmp, c As Range, arr, i
Set d = GetItemMap()
If d Is Nothing Then Exit Sub
Debug.Print d.Count
If d.Count = 0 Then
MsgBox "nothing found!"
Exit Sub
End If
For Each rw In myRange.Rows
tmp = rw.Cells(1).Value
If Len(tmp) > 0 Then
If d.exists(tmp) Then
arr = d(tmp)
For i = LBound(arr) To UBound(arr)
arr(i).Value = rw.Cells(2).Value
Next i
End If
End If
Next rw
End Sub
Function GetItemMap() As Object
Dim dict As Object, ws As Worksheet
Dim f As Range, lastRow As Long, tmp, arr, ub As Long
Set dict = CreateObject("scripting.dictionary")
For Each ws In ThisWorkbook.Worksheets
Set f = ws.Rows(1).Find(what:="Order-Item", LookIn:=xlValues, _
LookAt:=xlWhole)
If Not f Is Nothing Then
Set f = f.Offset(1, 0)
lastRow = ws.Cells(Rows.Count, f.Column).End(xlUp).Row
Do While f.Row <= lastRow
tmp = Trim(f.Value)
If Len(tmp) > 0 Then
If Not dict.exists(tmp) Then
dict.Add tmp, Array(f.Offset(0, 1))
Else
'can same item# exist > once?
arr = dict(tmp)
ub = UBound(arr) + 1
ReDim Preserve arr(0 To ub)
Set arr(ub) = f.Offset(0, 1)
dict(tmp) = arr
End If
End If
Set f = f.Offset(1, 0)
Loop
Else
MsgBox ("Couldn't find 'Order-Item' in Header!")
Exit Function
End If
Next ws
Set GetItemMap = dict
End Function

Related

VBA File Collections need to only add specific files

I have never worked with file collections before, but I was able to find the code below (https://danwagner.co/how-to-combine-multiple-excel-workbooks-into-one-worksheet-with-vba/). I have a file location that could have over 120+ files. I needed the sub to browse to that file location, loop through the files and copy/append data to a new workbook. And that parts works perfectly. My issue is that I don't need it to add all the files to the collection. Each filename begins with a 4 digit year, i.e. 2019_M05 (meaning May of 2019). I only need it to look at the past 7 years files. Ive tried using an if on the strFile name, but it locks my excel every time. Unfortunately, they need all the data in one file and it could be over 500k lines. Any suggestions would be appreciated.
Public Sub Create820Accumulatorfile()
Dim wb1 As Workbook
Dim strDirContainingFiles As String, strFile As String, _
strFilePath As String, stryears 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
Dim StartingTime As Single
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculate = xlCalculationManual
Set wb1 = ThisWorkbook
StartingTime = Timer
'Set references up-front
strDirContainingFiles = wb1.Sheets("Start Here").Range("B11").Value '<~ your folder
stryears = wb1.Sheets("Start Here").Range("B12").Value '<~ years for files to include
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 & "\*.xlsx")
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("Excel_Destination") '<~ change based on your Sheet name
'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
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculate = xlCalculationAutomatic
'Let the user know that the combination is done!
MsgBox "Data combined! " & Format((Timer - StartingTime) / 86400, "hh:mm:ss")
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
I know I need to add it in this section of the code. I tried creating a variable to hold the year of the file and it tests against a user inputted starting date, but the loop is going through 100+ files and it crashes my excel. I don't get any errors other than the crash.
'Store all of the file names in a collection
Dim fileyear as long
strFile = Dir(strDirContainingFiles & "\*.xlsx")
Do While Len(strFile) > 0
fileyear = left(strFile, 2)
if fileyear >= wb1.Sheets("Start Here").Range("B12").Value then
colFileNames.Add Item:=strFile
strFile = Dir
end if
Loop
Writing Consecutive Numbers to a Dictionary
The following is something like the idea presented by Daniel DuĊĦek in the comments.
Here is a great dictionary resource. Here is a Youtube playlist from the same author.
Dim YearsCount As Long
YearsCount = wb1.Sheets("Start Here").Range("B12").Value
Dim LastYear As Long: LastYear = Year(Date) ' current year...
' ... or read from a cell like the years count
Dim dictYears As Object
Set dictYears = CreateObject("Scripting.Dictionary")
Dim y As Long
For y = 0 To YearsCount - 1
dictYears(CStr(LastYear - y)) = Empty
Next y
strFile = Dir(strDirContainingFiles & "\*.xlsx")
Do While Len(strFile) > 0
If dict.Exists(Left(strFile, 4)) Then
colFileNames.Add Item:=strFile
strFile = Dir
End If
Loop

Highlighting Values In Column to Column Comparison using VBA

I am attempting to compare two columns in two separate sheets, each column contains data that is a string. My issue is that there is data in one column that is identical to the other in separate rows; therefore I have to check the entire column for the data before moving to the next. I am very inexperienced with VBA and am trying to make one portion of my job easier rather than comparing the columns by hand. I have piece wised the following code from research and trial and error. I am able to get the entire Column searched in my first Sheet, but only one value is being highlighted on the second sheet and then it is returning a value of "True" in the first column. I am unsure where I have gone wrong, any help is greatly appreciated!
Sub Better_Work_This_Time()
Dim FindString As String
Dim Rng As Range
ActiveCell = Sheets("Last Week").Range("A2").Activate
FindString = ActiveCell
Dim County As Integer
Count = Cells.CurrentRegion.rows.Count
For i = 2 To County
If Trim(FindString) <> "" Then
With Sheets("Current Week").Range("A:A")
Set Rng = .Find(What:=FindString, After:=.Cells(.Cells.Count), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=True)
If Not Rng Is Nothing Then
ActiveCell.Font.Color = vbBlue
End If
End With
End If
If IsEmpty(FindString) Then
FindString = False
End If
ActiveCell.Offset(1, 0).Select
i = i + 1
Next
End Sub
Without using ActiveCell and using Match instead of Find.
Option Explicit
Sub Does_Work_This_Time()
Dim wb As Workbook, wsLast As Worksheet, wsCurrent As Worksheet
Dim FindString As String, ar, v
Dim LastRow As Long, i As Long, n As Long
Set wb = ThisWorkbook
' put current week values into array
Set wsCurrent = wb.Sheets("Current Week")
With wsCurrent
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
ar = .Range("A2:A" & LastRow).Value2
End With
' scan last week matching current week
Set wsLast = wb.Sheets("Last Week")
With wsLast
.Columns(1).Interior.Color = xlNone
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
FindString = Trim(.Cells(i, "A"))
If Len(FindString) > 0 Then
v = Application.Match(FindString, ar, 0)
If IsError(v) Then
'no match
ElseIf ar(v, 1) = FindString Then ' case match
.Cells(i, "A").Interior.Color = RGB(128, 255, 128) ' light green
n = n + 1
End If
End If
Next
End With
MsgBox n & " rows matched"
End Sub

Deleting Preceding Blank Columns and Rows

I am trying to write a VBA code to cycle through each sheet in the active workbook and delete all blank columns and rows leading up to the first cell with data. For example, if the first cell with data is D5, columns A-C and Rows 1-4 would be deleted leaving the data starting in A1. I have the code below which works for the active sheet but I can't figure out how to get it to loop through the other sheets.
Sub DeleteRowsColumns()
' This will delete all Blank Columns and Rows before any data
Dim ColCounter As Long
Dim RowCounter As Long
Dim SafeCount As Integer
Dim ws As Worksheet
SafeCount = 0
' Check Column A is empty if Yes then Delete till A is populated
For Each ws In ActiveWorkbook.Worksheets
Do While ColCounter = 0
SafeCount = SafeCount + 1
ColCounter = Application.CountA(Columns(1).EntireColumn)
If ColCounter = 0 Then
Columns(1).EntireColumn.Delete
End If
If SafeCount = 50 Then
Exit Do
End If
Loop
Next ws
' Check Row 1 is empty if Yes then Delete till 1 is populated
For Each ws In ActiveWorkbook.Worksheets
SafeCount = 0
Do While RowCounter = 0
SafeCount = SafeCount + 1
RowCounter = Application.CountA(Rows(1).EntireRow)
If RowCounter = 0 Then
Rows(1).EntireRow.Delete
End If
If SafeCount = 50 Then
Exit Do
End If
'Loop
Next ws
MsgBox "Removed Preceding Blank Rows and Columns"
End Sub
Within each loop you need to specify which worksheet you are performing the operations on. Just looping through doesn't solve the problem. For instance:
ColCounter = Application.CountA(ws.Columns(1).EntireColumn)
If ColCounter = 0 Then
ws.Columns(1).EntireColumn.Delete
This ensures you are working in the correct worksheet.
Add it to a loop.
For X = 1 To 50
For i = 1 To 50
ColCounter = Application.CountA(ws.Columns(i).EntireColumn)
If ColCounter = 0 Then
ws.Columns(i).EntireColumn.Delete
End If
rowCounter = Application.CountA(ws.Rows(i).EntireRow)
If rowCounter = 0 Then
ws.Rows(i).EntireRow.Delete
End If
Next i
Next X
You could avoid any looping by first finding where the content starts (by row and then by column)
Sub RemoveEmpties()
Dim f As Range, f2 As Range, ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
'first occupied cell on sheet (by row)
Set f = ws.Cells.Find(What:="*", After:=ws.Cells(ws.Rows.Count, ws.Columns.Count), _
LookAt:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not f Is Nothing Then
'have content, so find first-occupied column
Set f2 = ws.Cells.Find(What:="*", After:=ws.Cells(ws.Rows.Count, ws.Columns.Count), _
LookAt:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, MatchCase:=False)
'remove rows/columns as required
If f.Row > 1 Then ws.Cells(1, 1).Resize(f.Row - 1).EntireRow.Delete
If f2.Column > 1 Then ws.Cells(1, 1).Resize(, f2.Column - 1).EntireColumn.Delete
End If
Next ws
End Sub
Alternatively (again only max of two deletes):
Sub RemoveEmpties2()
Dim ws As Worksheet, r As Long, c As Long
For Each ws In ActiveWorkbook.Worksheets
'first make sure there's some content on the sheet...
If Application.CountA(ws.Cells) > 0 Then
r = 1: c = 1
Do While Application.CountA(ws.Rows(r)) = 0
r = r + 1
Loop
If r > 1 Then ws.Rows(1).Resize(r - 1).Delete
Do While Application.CountA(ws.Columns(c)) = 0
c = c + 1
Loop
If c > 1 Then ws.Columns(1).Resize(, c - 1).Delete
End If
Next ws
End Sub
Using the Find Method
The Flow
In the procedure delFirstBlank the workbook is defined. A worksheet variable is declared. In the following For Each Next loop, for each worksheet in the workbook, the procedure deleteFirstBlank is called. When the loop exits, by a message box, the user is informed that the code has finished.
In the deleteFirstBlank procedure, the result of the function getFirstRow is written to a variable. The variable is then tested if it is equal to 0 i.e. the worksheet is blank. If so, then the procedure is exited. If not, the variable is tested if it is greater than 1 i.e. if at least the first row is empty. If so, the rows from the first row to the row defined by the variable decreased by one are deleted. Then the result of the function getFirstRow is written to a variable which is tested if it is greater than 1 i.e. if at least the first column is empty. If so, the columns from the first column to the column defined by the variable decreased by one are deleted.
In the getFirstRow procedure (function) a range variable is declared. Using the Find method, searching by rows, the first found non-blank cell (range) in the supplied worksheet, is assigned to the range variable. If the result of the Find method was a cell range, its row is written as the result of the function. If not, 0 is written as the result i.e. the worksheet is blank.
In the getFirstColumn procedure (function) a range variable is declared. Using the Find method, searching by columns, the first found non-blank cell (range) in the supplied worksheet, is assigned to the range variable. If the result of the Find method was a cell range, its column is written as the result of the function. If not, 0 is written as the result i.e. the worksheet is blank (the latter will never happen, because the worksheet was already tested if it is blank in the 'getFirstRow' procedure).
The Code
Option Explicit
Sub delFirstBlank()
Dim wb As Workbook
Set wb = ActiveWorkbook
Dim ws As Worksheet
For Each ws In wb.Worksheets
deleteFirstBlank ws
Next ws
MsgBox "Removed first blank rows and columns.", vbInformation, "Success"
End Sub
Sub deleteFirstBlank(Sheet As Worksheet)
Dim Current As Long
Current = getFirstRow(Sheet)
If Current = 0 Then GoTo ProcExit ' Blank sheet.
If Current > 1 Then
Sheet.Range(Sheet.Rows(1), Sheet.Rows(CLng(Current) - 1)).Delete
End If
Current = getFirstColumn(Sheet)
If Current > 1 Then
Sheet.Range(Sheet.Columns(1), Sheet.Columns(CLng(Current) - 1)).Delete
End If
ProcExit:
End Sub
Function getFirstRow(Sheet As Worksheet) As Long
Dim rng As Range
Set rng = Sheet.Cells.Find(What:="*", _
After:=Sheet.Cells(Sheet.Rows.Count, _
Sheet.Columns.Count), _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows)
If Not rng Is Nothing Then
getFirstRow = rng.Row
Else
getFirstRow = 0 ' Blank Sheet
End If
End Function
Function getFirstColumn(Sheet As Worksheet) As Long
Dim rng As Range
Set rng = Sheet.Cells.Find(What:="*", _
After:=Sheet.Cells(Sheet.Rows.Count, _
Sheet.Columns.Count), _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns)
If Not rng Is Nothing Then
getFirstColumn = rng.Column
Else
getFirstColumn = 0 ' Blank Sheet
End If
End Function

Excel-VBA Copy image from worksheet1 to worksheet 2

I am having difficulty getting the code in the workbook attached to function as intended. Everything is working but it is copying the photo twice. Any suggestions?
Basically, it looks at the master worksheet then creates a unique sheet for each supplier based on the date entered and copies over all records to the next empty line. What is happening is that it copies the photo over but it pastes it twice. I can't figure out why.
Code is shown in attached workbook.
Option Explicit
Const ColSht1Name As Long = 1
Const RowSht1DataFirst As Long = 2
Const ColSht1Date As Date = 3
Const ColSht1Doc As String = 4
Sub BuildSingleSupplierSheets()
' For each supplier in worksheet Sheet1, create their own worksheet.
' Copy each data row for a supplier, including a picure if any, to its own worksheet.
Dim ColSht1LastHdr As Long
Dim ColSht1LastCrnt As Long
Dim ColShapeTopLeftCell As Long
Dim Found As Boolean
Dim HeightShape As Single
Dim InxShape As Long
' Dim RowPerPicture() As String
Dim RngDest As Range
Dim RowCrntNext As Long
Dim RowSht1Crnt As Long
Dim RowSht1Last As Long
Dim ShapeCrnt As Shape
Dim WshtSht1 As Worksheet
Dim WshtCrnt As Worksheet
Dim WshtNameCrnt As String
Dim x As String
Dim bottomL As Integer
Dim c As Range
Set WshtSht1 = Worksheets("Sheet1")
x = InputBox("Enter Report Date")
With Worksheets("Sheet1")
RowSht1Last = .Cells(Rows.Count, ColSht1Name).End(xlUp).Row
ColSht1LastHdr = 0
For RowSht1Crnt = 1 To RowSht1DataFirst - 1
ColSht1LastCrnt = .Cells(RowSht1Crnt, Columns.Count).End(xlToLeft).Column
If ColSht1LastHdr < ColSht1LastCrnt Then
ColSht1LastHdr = ColSht1LastCrnt
End If
Next
End With
' Copy every row from worksheet Sheet1 to the worksheet for the row's
' supplier. Create and initialise supplier worksheet if it does not
' already exist.
For RowSht1Crnt = RowSht1DataFirst To RowSht1Last
If WshtSht1.Cells(RowSht1Crnt, ColSht1Date).Value = x And WshtSht1.Cells(RowSht1Crnt, "B").Value = "DR" Then
WshtNameCrnt = WshtSht1.Cells(RowSht1Crnt, ColSht1Name).Value
' Create and initiialise worksheet WshtNameCrnt if it does not already exist
If Not SheetExists(WshtNameCrnt) Then
Set WshtCrnt = Worksheets.Add(After:=Worksheets(Worksheets.Count))
WshtCrnt.Name = WshtNameCrnt
With WshtSht1
.Range(.Cells(1, 1), .Cells(RowSht1DataFirst - 1, ColSht1LastHdr)).Copy _
Destination:=WshtCrnt.Range("A1")
End With
Else
Set WshtCrnt = Worksheets(WshtNameCrnt)
End If
' Copy current row of worksheet Sheet1 to the next free row
' of the supplier worksheet
RowCrntNext = LastRow(WshtCrnt) + 1
With WshtSht1
ColSht1LastCrnt = .Cells(RowSht1Crnt, Columns.Count).End(xlToLeft).Column
.Range(.Cells(RowSht1Crnt, 1), .Cells(RowSht1Crnt, ColSht1LastCrnt)).Copy _
Destination:=WshtCrnt.Cells(RowCrntNext, 1)
End With
' Ensure columns wide enought for data
With WshtCrnt
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).EntireColumn.AutoFit
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlInsideHorizontal).Color = RGB(0, 0, 0)
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlInsideVertical).Color = RGB(0, 0, 0)
End With
' Check Shapes collection to see if there is a picture on this row
With WshtSht1
Found = False
For InxShape = 1 To .Shapes.Count
With .Shapes(InxShape)
If .Type = msoPicture Then
If .TopLeftCell.Row = RowSht1Crnt Then
Found = True
Exit For
End If
End If
End With
Next
End With
If Found Then
' Picture on current row of Sheet1. Copy to supplier worksheet
Set ShapeCrnt = WshtSht1.Shapes(InxShape)
With ShapeCrnt
ColShapeTopLeftCell = .TopLeftCell.Column
HeightShape = .Height
End With
ShapeCrnt.Copy
WshtCrnt.Paste
With WshtCrnt
Set RngDest = .Cells(RowCrntNext, ColShapeTopLeftCell)
RngDest.RowHeight = HeightShape + 4!
With .Shapes(.Shapes.Count)
.Top = RngDest.Top + 2!
.Left = RngDest.Left + 2!
Call .ScaleWidth(1!, msoCTrue) '
Call .ScaleHeight(1!, msoCTrue) '
End With
End With
End If
End If
Next RowSht1Crnt
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
Function SheetExists(SName As String, _
Optional ByVal WB As Workbook) As Boolean
'Chip Pearson
On Error Resume Next
If WB Is Nothing Then Set WB = ThisWorkbook
SheetExists = CBool(Len(WB.Sheets(SName).Name))
End Function
Workbook Example
You have 2 paste operations in your code. One that you know of:
WshtCrnt.Paste
and one that is part of this range copy statement:
.
.
With WshtSht1
.Range(.Cells(1, 1), .Cells(RowSht1DataFirst - 1, ColSht1LastHdr)).Copy_
Destination:=WshtCrnt.Range("A1")
.
.
By specifying a "Destination" you are requesting a copy AND paste of your range.

Splitting a cell column value before comparison

I have two spreadsheets, vda.xlsx and main.xlsm. At the moment I'm comparing the values in:
main.xlsm column J
with
vda.xlsx column A
To see if there is a match. If a match is found then the value in column gets highlighted in red.
However the format of the data in vda.xlsx column A has changed .
It used to look like this
1234
Now it looks like this
Test\1234 or Best\1234 or Jest\1234 - it could be anything...
Sp I need to split Test\1234 by the "\" and extract 1234 for comparison.
Any idea how I can accomplish this. This is my code so far:
Sub VDA_Update()
Dim wshT As Worksheet
Dim wbk As Workbook
Dim wshS As Worksheet
Dim r As Long
Dim m As Long
Dim cel As Range
Application.ScreenUpdating = False
Set wshT = ThisWorkbook.Worksheets("Master")
On Error Resume Next
' Check whether vda.xlsx is already open
Set wbk = Workbooks("vda.xlsx")
On Error GoTo 0
If wbk Is Nothing Then
' If not, open it
Set wbk = Workbooks.Open("C:\Working\vda_test.xlsx")
End If
' Set worksheet on vda.xlsx
Set wshS = wbk.Worksheets("imac01")
m = wshT.Cells(wshT.Rows.Count, 1).End(xlUp).Row
' Loop though cells in column J on main.xlsm
For r = 1 To m
' Can we find the value in column C of vda.xlsx?
Set cel = wshS.Columns(1).Find(What:=wshT.Cells(r, 10).Value, _
LookAt:=xlWhole, MatchCase:=False)
If Not cel Is Nothing Then
' If we find a match, then change the text to red
wshT.Cells(r, 10).Font.ColorIndex = 3
End If
Next r
Application.ScreenUpdating = True
End Sub
Use Split(CellValue, "\") to get an array and then retrieve the last item in the array.
Change:
' Loop though cells in column J on main.xlsm
For r = 1 To m
' Can we find the value in column C of vda.xlsx?
Set cel = wshS.Columns(1).Find(What:=wshT.Cells(r, 10).Value, _
LookAt:=xlWhole, MatchCase:=False)
If Not cel Is Nothing Then
' If we find a match, then change the text to red
wshT.Cells(r, 10).Font.ColorIndex = 3
End If
Next r
To something like:
' Loop though cells in column A on vda.xlsx
For r = 1 To m
' Can we find the value in column J of main.xlsm?
cellSplit = Split(wshS.Cells(r, 1).Value, "\")
Set cel = wshT.Columns(10).Find(cellSplit(UBound(cellSplit)), _
LookAt:=xlWhole, MatchCase:=False)
If Not cel Is Nothing Then
' If we find a match, then change the text to red
cel.Cells(1, 1).Font.ColorIndex = 3
End If
Next r

Resources