VBA function not calling correctly - excel

I have the following function which finds the last row in a worksheet and am trying to call it in my Sub Submit_data(). The sub doesn't seem to recognise it and so the message box returns 0. However, if I place the exact same code in a test sub with nothing else in it it works. Anyone have any idea why this would be? note: my submit data sub is longer so I have just included the the first portion where the error occurs.
Private Function lasrow() As Long
Worksheets("Data - Complete").Select
lasrow = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End Function
Sub Submit_data()
Dim lRow As Long
Dim lCol As Long
Dim colName As Long
Dim resetrange As Range
Dim indicator As String
Dim Dire(1 To 6, 1 To 2) As String
Dim i As Integer
Dim lasrow As Long, lasCol As Long
Dim lro As Long
Dire(1, 1) = "B2": Dire(1, 2) = "D2"
Dire(2, 1) = "B3": Dire(2, 2) = "D3"
Dire(3, 1) = "B4": Dire(3, 2) = "D4"
Dire(4, 1) = "G7": Dire(4, 2) = "I7"
Dire(5, 1) = "G11": Dire(5, 2) = "I11"
Dire(6, 1) = "G13": Dire(6, 2) = "I13"
Application.ScreenUpdating = False
If IsEmpty(Range("I15")) = False Then
lro = lasrow
Worksheets("User").Select
Range("I15").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Data - Complete").Select
Cells(lro + 1, 5).Select 'problem with selecting column
ActiveSheet.Paste
Worksheets("User").Select
Range("I15").Select
Selection.ClearContents
MsgBox ("lRow is " & lro)
End If

Just to sum things up:
To fix the problem you are having you need to remove the variable declaration that has the same name as your function.
To make it even simpler you can just remove the function and have your sub like this:
Sub Submit_data()
Dim lRow As Long
Dim lCol As Long
Dim colName As Long
Dim resetrange As Range
Dim indicator As String
Dim Dire(1 To 6, 1 To 2) As String
Dim i As Integer
Dim lasCol As Long
Dim lro As Long
Dire(1, 1) = "B2": Dire(1, 2) = "D2"
Dire(2, 1) = "B3": Dire(2, 2) = "D3"
Dire(3, 1) = "B4": Dire(3, 2) = "D4"
Dire(4, 1) = "G7": Dire(4, 2) = "I7"
Dire(5, 1) = "G11": Dire(5, 2) = "I11"
Dire(6, 1) = "G13": Dire(6, 2) = "I13"
Application.ScreenUpdating = False
If IsEmpty(Range("I15")) = False Then
'Change this so find the last row without the function
'The "1" is telling it to look in column "A"
'The ActiveSheet.Rows.Count is using the maximum number of possible rows as the row which is 1048576
'So it is starting in A1048576 and going up till it finds the first non-empty row and returning that row number
lro = ActiveSheet.Cells(ActiveSheet.Rows.count, 1).End(xlUp).row
Worksheets("User").Select
Range("I15").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Data - Complete").Select
Cells(lro + 1, 5).Select 'problem with selecting column
ActiveSheet.Paste
Worksheets("User").Select
Range("I15").Select
Selection.ClearContents
MsgBox ("lRow is " & lro)
End If
and you still don't need the lasrow variable with what is showing here.

Related

Highlight if 2 different values in a cell

would anyone be able to help?
I am trying to write VBA to highlight if the cell has 2 different values. It seems to highlight all including the same name appear twice. Thanks for any help!
Sub CountTwoOrMoreDifferent()
Dim myRange As Long
myRange = Cells(Rows.Count, "A").End(xlUp).Row
Range("A2:A" & myRange).Select
For Each AnimalName In Selection
AnimalNameMoreThan2 = AnimalName.Value
If InStr(AnimalNameMoreThan2, "Cat") + _
InStr(AnimalNameMoreThan2, "Dog") + _
InStr(AnimalNameMoreThan2, "Cow") _
+ InStr(AnimalNameMoreThan2, "Chicken") + _
InStr(AnimalNameMoreThan2, "Snake") + _
InStr(AnimalNameMoreThan2, "Tums") + _
InStr(AnimalNameMoreThan2, "Drop") > 1 Then
AnimalName.Interior.Color = vbRed
End If
Next AnimalName
End Sub
Data in column A
Sample Data
You can use this code.
It is split into two parts
a sub - which does the check per cell.
a function that checks if there is a duplicate within an array.
It returns true in case there is at least one dup.
Public Sub highlightDuplicateValues()
'get Range to check
Dim lastRow As Long, rgToCheck As Range
With ActiveSheet
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rgToCheck = .Range("A2:A" & lastRow) 'no need to select!
End With
Dim c As Range, arrValuesInCell As Variant
Dim i As Long
For Each c In rgToCheck.Cells
'get an array of values/animals in cell
arrValuesInCell = Split(c.Value, ";")
'now check for each value if it has a dup - if yes color red and exit check
For i = LBound(arrValuesInCell) To UBound(arrValuesInCell)
If hasDupInArray(arrValuesInCell, i) = True Then
c.Interior.Color = vbRed
Exit For
End If
Next
Next
End Sub
Private Function hasDupInArray(arrValues As Variant, checkI As Long) As Boolean
'only values after the checkI-value are checked.
'Assumption: previous values have been checked beforehand
Dim varValueToCheck As Variant
varValueToCheck = arrValues(checkI)
Dim i As Long
For i = checkI + 1 To UBound(arrValues)
If arrValues(i) = varValueToCheck Then
hasDupInArray = True
Exit For
End If
Next
End Function

Loop the code till the cell is empty in excel

I stuck with this problem:
I have this code and it works but I struggle now.
I want the loop this whole code till in Table1 the cell D1 is empty.
Sub strule()
Dim myCellRange As Range
Worksheets("Table1").Select
Code = Range("D1")
Wert = Range("E10")
Worksheets("Table2").Select
Worksheets("Table2").Range("A1").Select
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
Range("A" & lMaxRows).Select
ActiveCell.Offset(1, 0).Select
ActiveCell.Value = Code
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = Wert
Sheets("Table1").Select '
Rows("1:10").Select
Selection.Cut
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
End Sub
I've had a guess at what you want... could be completely wrong though.
First of all your original code with all the selecting & activating removed:
Sub strule()
Dim WrkSht1 As Worksheet
Set WrkSht1 = Worksheets("Table1")
'Worksheets("Table1").Select
Dim Code As String
Code = WrkSht1.Range("D1")
Dim Wert As String
Wert = WrkSht1.Range("E10")
Dim WrkSht2 As Worksheet
Set WrkSht2 = Worksheets("Table2")
'Worksheets("Table2").Select
'Worksheets("Table2").Range("A1").Select
Dim lMaxRows As Long
lMaxRows = WrkSht2.Cells(Rows.Count, "A").End(xlUp).Row
WrkSht2.Cells(lMaxRows + 1, 1) = Code 'Lastrow+1 in column A.
WrkSht2.Cells(lMaxRows + 1, 2) = Wert 'Lastrow+1 in column B.
'Range("A" & lMaxRows).Select
'ActiveCell.Offset(1, 0).Select
'ActiveCell.Value = Code
'ActiveCell.Offset(0, 1).Select
'ActiveCell.Value = Wert
WrkSht1.Rows("1:10").Delete shift:=xlUp
'Sheets("Table1").Select '
'Rows("1:10").Select
'Selection.Cut
'Application.CutCopyMode = False
'Selection.Delete Shift:=xlUp
End Sub
Now what I think you want:
Sub strule1()
Dim WrkSht1 As Worksheet
Set WrkSht1 = Worksheets("Table1")
Dim WrkSht2 As Worksheet
Set WrkSht2 = Worksheets("Table2")
Dim lLastRow1 As Long
lLastRow1 = WrkSht1.Cells(Rows.Count, "A").End(xlUp).Row
Dim x As Long
Dim lLastRow2 As Long
Dim Code As String
Dim Wert As String
For x = 1 To lLastRow1 Step 10
Code = WrkSht1.Cells(x, 4) 'Loop 1 grabs from row 1, loop 2 from row 11
Wert = WrkSht1.Cells(x + 9, 5) 'Loop 1 grabs from row 10, loop 2 from row 20
lLastRow2 = WrkSht2.Cells(Rows.Count, "A").End(xlUp).Row
WrkSht2.Cells(lLastRow2 + 1, 1) = Code 'Lastrow+1 in column A.
WrkSht2.Cells(lLastRow2 + 1, 2) = Wert 'Lastrow+1 in column B.
Next x
WrkSht1.Rows("1:" & x).Delete shift:=xlUp
End Sub

Search for all values between 2 values in a column and loop till last one found

Lets start with I am self taught in Excel VBA and have a question that might seem stupid or basic:
I have the following information on a sheet:
[ConfBlastPlan]
DRB1065
PU1962;427;05_37_OB;A;2;2;1
PU1963;364;05_37_OB;B;2;2;1
PU1959;373;05_37_OB;C;2;2;1
-
[FiringProcedure]11:55:21;MULTI
What I want to do is combine all strings between with "PU" and the first ";" that is found between the
"[ConfBlastPlan]" and [FiringProcedure] into one cell.
I have read up about the loop function but seems I have confused myself terribly.
How do I loop this and combine the strings found?
I have started the function using the following code:
Sub DRBEquipNumberPU() 'GET THE PU#s
Dim WSFrom As Worksheet
Dim WSTo As Worksheet
Dim RngFrom As Range
Dim RngTo As Range
Dim BlastNumber As String
Dim BlastNumberStep As Long
Dim SearchString As String
Dim SearchStringStart As String
Dim SearchStringEnd As String
Dim LineStep As Long
Dim Blastedrng As Range
Dim BlastedFoundrng As Range
Dim closePos As Integer
BlastNumberStep = 1
LineStep = 1
Set Blastedrng = ThisWorkbook.Worksheets("Blast Summary Sheet").Range("A2", Range("A2").End(xlDown))
For Each BlastedFoundrng In Blastedrng.Cells
On Error Resume Next
SearchString = "[ConfBlastPlan]"
SearchStringStart = "PU"
SearchStringEnd = "[FiringProcedure]"
BlastNumber = CStr("Blasted " & BlastNumberStep)
Set WSFrom = Worksheets(CStr(BlastNumber))
Set RngFrom = WSFrom.Cells.Find(What:=SearchString, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
Set RngFrom1 = WSFrom.Cells.Find(What:=SearchStringStart, After:=RngFrom, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
Set WSTo = ThisWorkbook.Worksheets("Blast Summary Sheet")
Set RngTo = WSTo.Cells.Find(What:=(CStr(BlastNumber)), LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
closePos = InStr(1, RngFrom.Cells.Value, ";")
If RngTo.Cells.Offset(0, 4).Value = "INCOMPLT" Then
RngTo.Cells.Offset(0, 7).Value = "INCOMPLT"
ElseIf RngFrom.Cells.Value Is Nothing Then
RngTo.Cells.Offset(0, 7).Value = "NO PU #s"
ElseIf RngFrom.Cells.Value Like SearchStringStart Then
RngTo.Cells.Offset(0, 7).Value = Mid(RngFrom.Cells.Value, 0, closePos)
ElseIf RngFrom.Cells.Value = SearchStringEnd Then
End If
BlastNumberStep = BlastNumberStep + 1
Next BlastedFoundrng
End Sub
All it returns at the moment is INCOMPL or NO PU #s
There can be a maximum of 48 instances of PU
Please help
Blasted 23:
Blasted 26:
Blasted 27:
Option Explicit
' Major changes: make it two steps-- 1)Get all Sheet names, 2)Process all Lines on one sheet
Sub StepThruBlastedSheetNames() 'GET THE PU#s
Dim WSSummary As Worksheet, rowSummary As Long
Set WSSummary = ThisWorkbook.Worksheets("Blast Summary Sheet")
rowSummary = 1
Dim WSFrom As Worksheet
For Each WSFrom In ThisWorkbook.Worksheets
If InStr(WSFrom.Name, "Blasted ") > 0 Then
StepThruBlastedLines WSSummary, rowSummary, WSFrom
End If
Next
End Sub
Sub StepThruBlastedLines(WSSummary As Worksheet, rowSummary As Long, WSFrom As Worksheet)
' these never change, ergo do not put inside loop
Const SearchStringStart As String = "[ConfBlastPlan]"
Const SearchStringFindPU As String = "PU"
Const SearchStringEnd As String = "[FiringProcedure]"
Dim rowFrom As Long
Dim rowMax As Long
rowMax = WSFrom.Cells(WSFrom.Rows.Count, "A").End(xlUp).Row
Dim IsBetween As String, PUlist As String, posSemi As Long, DRBname As String
IsBetween = "N"
PUlist = ""
DRBname = ""
For rowFrom = 1 To rowMax
If IsBetween = "Y" Then
If InStr(WSFrom.Cells(rowFrom, "A"), "DRB") > 0 Then
DRBname = WSFrom.Cells(rowFrom, "A")
End If
If InStr(WSFrom.Cells(rowFrom, "A"), SearchStringFindPU) > 0 Then
posSemi = InStr(WSFrom.Cells(rowFrom, "A"), ";")
PUlist = PUlist & Mid(WSFrom.Cells(rowFrom, "A"), 1, posSemi)
End If
If InStr(WSFrom.Cells(rowFrom, "A"), SearchStringEnd) > 0 Then
IsBetween = "N"
rowSummary = rowSummary + 1
WSSummary.Cells(rowSummary, "A") = WSFrom.Name
WSSummary.Cells(rowSummary, "B") = DRBname
If PUlist <> "" Then
WSSummary.Cells(rowSummary, "C") = PUlist
PUlist = ""
Else
'<< add put empty notice
WSSummary.Cells(rowSummary, "C") = "INCOMPL"
End If
DRBname = "" '<<added
End If
ElseIf WSFrom.Cells(rowFrom, "A") = SearchStringStart Then
IsBetween = "Y"
End If
Next rowFrom
End Sub
Here's code that extracts the PU-values from a worksheet like the one you posted. I couldn't figure out why you called this worksheet WsTo and perhaps that's the reason why I also couldn't guess at your intention for what to do with the result. Your question is mute on the point. So I left the project at that point. I'm sure you will be able to pick it up from the two ways I'm displaying the Output array.
Sub DRBEquipNumberPU()
' 134
' Get the PU#s
Const Blast As String = "[ConfBlastPlan]"
Const BlastEnd As String = "-"
Const Marker As String = "PU"
Dim WsTo As Worksheet
Dim BlastFound As Range
Dim CellVal As String ' loop variable: Cell.Value
Dim R As Long ' loop counter: rows
Dim Output As Variant ' array of found values
Dim i As Long ' index to Output
Set WsTo = ThisWorkbook.Worksheets("Blast Summary Sheet")
With WsTo.Columns(1)
Set BlastFound = .Find(What:=Blast, _
LookIn:=xlValues, _
Lookat:=xlWhole, _
MatchCase:=False)
If BlastFound Is Nothing Then
MsgBox """" & Blast & """ wasn't found.", _
vbInformation, "No data to process"
Else
ReDim Output(1 To 100) ' choose UBound larger than you ever need
R = BlastFound.Row
Do
R = R + 1
CellVal = .Cells(R).Value
If InStr(1, Trim(CellVal), Marker, vbTextCompare) = 1 Then
i = i + 1
Output(i) = CellVal
End If
Loop While Len(CellVal) And CellVal <> BlastEnd
If i Then
ReDim Preserve Output(1 To i)
MsgBox "Found values = " & vbCr & _
Join(Output, Chr(13))
For i = LBound(Output) To UBound(Output)
Debug.Print Output(i)
Next i
End If
End If
End With
End Sub
It just occurs to me that the end marker you suggested ("FiringProcedure]") may be more reliable than my choice ("-"). If so, just change it at the top of the code where the constants are declared. If that marker is missed the code might continue to include the "PU" line below the [Blasting Plan] row.

If Else statement only working for the last row of data in Excel VBA Userform

I'm struggling with something that sounds very simple, but there's something wrong with my code.
I have a userform with 2 textboxes when I type a 'serial number' in textbox 1, the 'RMA Number' in textbox 2 auto populates if the serial number matches an existing field in the 'RMA' column in the sheet.
If it does not match I want textbox2 to clear up or say "No Match"
I did the If-Then-Else type of code but it seems to work only for the very last entry at the moment...
What do I need to change in my code so it can match all the entries AND clear up when the Serial Number does not match??
'Autopopulate RMA# with Serial Number
Private Sub SN_TextBox1_Change()
Dim serial1_id As String
serial1_id = UCase(Trim(SN_TextBox1.Text))
lastrow = Worksheets("RMA Tracker").Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastrow
If UCase(Worksheets("RMA Tracker").Cells(i, 4).Value) = serial1_id Then
RMA_TextBox1.Text = Worksheets("RMA Tracker").Cells(i, 1).Value
Else
RMA_TextBox1.Value = ""
End If
Next i
End Sub
I think you can use Find() method to server your purpose. Below code will find TextBox1 value from RMA column (D:D). If match found then it will return value from Column A:A for matching row to TextBox2. If there is no match the it will show No Match message to TextBox2.
Private Sub CommandButton1_Click()
Dim RMA As String
Dim Rng As Range
RMA = Me.TextBox1
If Trim(RMA) <> "" Then
With Sheets("RMA Tracker").Range("D:D") 'D:D for column 4
Set Rng = .Find(What:=RMA, _
After:=.Range("A1"), _
Lookat:=xlWhole, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
If Not Rng Is Nothing Then
Me.TextBox2 = Rng.Offset(0, -3)
Else
Me.TextBox2 = "No Match"
End If
End With
End If
End Sub
Lookup Value in UserForm TextBox
To show multiple results, you have to set MultiLine to True in the properties of RMA_TextBox1.
The Code
Private Sub SN_TextBox1_Change()
Const wsName As String = "RMA Tracker"
Const FirstRow As Long = 1
Const RMACol As Variant = "A"
Const IdCol As Variant = "D"
Const IfNot As String = "No Match"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim LastRow As Long: LastRow = ws.Cells(ws.Rows.Count, IdCol).End(xlUp).Row
Dim SerialID As String: SerialID = Trim(SN_TextBox1.Value)
Dim i As Long, Result As String
For i = FirstRow To LastRow
If StrComp(ws.Cells(i, IdCol).Value, SerialID, vbTextCompare) = 0 Then
If Result <> "" Then
Result = Result & vbLf & ws.Cells(i, RMACol).Value
Else
Result = ws.Cells(i, RMACol).Value
End If
End If
Next i
If Result <> "" Then
RMA_TextBox1.Value = Result
Else
RMA_TextBox1.Value = IfNot
End If
End Sub

Copy data from a variable table

I have been trying to do a report and creating a macro to copy the data from one file to another.
I cannot figure out how to copy the data since the table I need to get my data from varies.
Example one:
What I need to copy is what is below the Alarm text.
But in, example one, I have no critical alarms but there are files that may have. Same applies to major/minor/warning.
The max of lines below the Alarm text are 3, but I can have 1/2/3 or even none.
In example 2, I have no data.
Here I have 2 critical and 3 on all other categories.
I know this may be a weird question, but I have no idea in how to find the these values, since they may vary so much.
All help is appreciated
Here is the code i have, but i am missing the important part,
Sub Copy()
Dim wbOpen As Workbook
Dim wbMe As Workbook
Dim vals As Variant
Set wbMe = ThisWorkbook
Set wbOpen = Workbooks.Open("C:\XXX\Core")
'MSS
vals = wbOpen.Sheets("MSS02NZF").Range("A2:B260").Copy
wbMe.Sheets("MSS02NZF").Range("B5").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
' wbOpen.Sheets(1).Range("A2:B260").Copy
' wbMe.Sheets(1).Range("B5").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'MME
vals = wbOpen.Sheets("MME01NZF").Range("A2:H260").Copy
wbMe.Sheets("MME01NZF").Range("B5").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'CSCF
vals = wbOpen.Sheets("CSCF").Range("A2:H2060").Copy
wbMe.Sheets("CSCF").Range("B5").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Modify to your own need; code is using A:B as your source, and pastes the results in C:D.
Sub test()
Dim lrow As Long, alarmRow() As Long, alarmEnd() As Long
Dim count As Long, count2 As Long, rowcount As Long
ReDim alarmRow(1 To Application.CountIf(Range("A:A"), "Alarm"))
ReDim alarmEnd(1 To UBound(alarmRow))
With Worksheets("Sheet4") 'Change this to the Sheetname of your source.
lrow = .Cells(Rows.count, 1).End(xlUp).Row
For x = 1 To lrow Step 1
If .Range("A" & x).Value = "Alarm" Then 'Change "A" column to where your source data is.
count = count + 1
alarmRow(count) = x + 1
ElseIf .Range("A" & x).Value = "" Then 'Change "A" column to where your source data is.
count2 = count2 + 1
alarmEnd(count2) = x
End If
alarmEnd(UBound(alarmEnd)) = lrow
Next
For x = 1 To UBound(alarmRow) Step 1
lrow = .Cells(Rows.count, 3).End(xlUp).Row + 1
rowcount = alarmEnd(x) - alarmRow(x)
.Range("C" & lrow & ":D" & lrow + rowcount).Value = .Range("A" & alarmRow(x) & ":B" & alarmEnd(x)).Value ' Change A/B to where your source data is, and C/D to where you want to put the list.
Next
End With
End Sub
It's a bit of a mess, but here's how it works:
It'll look at the list where the word "Alarm" is. Once it finds it, the row number the word is in is registered to an Array. The row of the blank space is also taken to another array. This will serve as the range when copying the data.
Array of Arrays feat. 3-dimensional Jagged Arrays
Option Explicit
'*******************************************************************************
' Purpose: If not open, opens a specified workbook and pastes specific data
' found in two columns from several worksheets into a range specified
' by a cell in worksheets with the same name in this workbook.
'*******************************************************************************
Sub CopyPasteArray()
'***************************************
' List of Worksheet Names in Both Workbooks
Const cStrWsName As String = "MSS02NZF,MME01NZF,CSCF"
' Separator in List of Names of Worksheets in Both Workbooks
Const cStrSplit As String = ","
' Path of Workbook to Be Copied From
Const cStrSourcePath As String = "C:\XXX"
' Name of Workbook to Be Copied From
Const cStrSourceName As String = "Core.xls"
' Address of First Row Range to Be Copied From
Const cStrSourceFirst As String = "A2:B2"
' Target Top Cell Address to Be Pasted Into
Const cStrTopCell As String = "B5"
' Search String
Const cStrSearch As String = "Alarm"
' Target Columns
Const cIntTargetCols As Integer = 2 ' Change to 3 to include Type of Error.
'***************************************
Dim objWbSource As Workbook ' Source Workbook
Dim vntWsName As Variant ' Worksheet Names Array
Dim vntSourceAA As Variant ' Source Array of Arrays
Dim vntTargetAA As Variant ' Target Array of Arrays
Dim vntTargetRows As Variant ' Each Target Array Rows Array
Dim vntTarget As Variant ' Each Target Array
Dim blnFound As Boolean ' Source Workbook Open Checker
Dim lngRow As Long ' Source Array Arrays Rows Counter
Dim intCol As Integer ' Source Array Arrays Columns Counter
Dim intArr As Integer ' Worksheets and Arrays Counter
Dim lngCount As Long ' Critical Data Counter
Dim lngCount2 As Long ' Critical Data Next Row Counter
Dim strPasteCell As String
'***************************************
' Paste list of worksheets names into Worksheet Names Array.
vntWsName = Split(cStrWsName, cStrSplit)
'***************************************
' Check if Source Workbook is open.
For Each objWbSource In Workbooks
If objWbSource.Name = cStrSourceName Then
Set objWbSource = Workbooks(cStrSourceName)
blnFound = True ' Workbook is open.
Exit For ' Stop checking.
End If
Next
' If Source Workbook is not open, open it.
If blnFound = False Then
Set objWbSource = Workbooks.Open(cStrSourcePath & "\" & cStrSourceName)
End If
'***************************************
' Paste data from Source Workbook into Source Array of Arrays.
ReDim vntSourceAA(UBound(vntWsName))
For intArr = 0 To UBound(vntWsName)
With objWbSource.Worksheets(vntWsName(intArr))
vntSourceAA(intArr) = _
.Range( _
.Range(cStrSourceFirst).Cells(1, 1) _
, .Cells( _
.Range( _
.Cells(1, .Range(cStrSourceFirst).Column) _
, .Cells(Rows.Count, .Range(cStrSourceFirst).Column _
+ .Range(cStrSourceFirst).Columns.Count - 1)) _
.Find(What:="*", _
After:=.Range(cStrSourceFirst).Cells(1, 1), _
LookIn:=xlFormulas, Lookat:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious _
).Row _
, .Range(cStrSourceFirst).Column _
+ .Range(cStrSourceFirst).Columns.Count - 1 _
) _
).Value2
End With
Next
' The Source Array of Arrays is a 3-dimensional (jagged) array containing
' a 0-based 1-dimensional array containing an 'UBound(vntWsName)' number of
' 1-based 2-dimensional arrays.
'***************************************
' Count the number of critical data rows to determine size
' of each Target Array.
ReDim vntTargetRows(UBound(vntWsName))
For intArr = 0 To UBound(vntSourceAA)
For lngRow = 1 To UBound(vntSourceAA(intArr), 1)
If vntSourceAA(intArr)(lngRow, 1) = cStrSearch Then
For lngCount2 = lngRow + 1 To UBound(vntSourceAA(intArr), 1)
If vntSourceAA(intArr)(lngCount2, 1) <> "" Then
' Debug.Print vntSourceAA(intArr)(lngCount2, 1)
lngCount = lngCount + 1
lngRow = lngRow + 1
Else
Exit For
End If
Next
End If
Next
vntTargetRows(intArr) = lngCount
lngCount = 0
Next
'***************************************
' Copy critical data into each Target Array and paste it into
' Target Array of Arrays.
ReDim vntTargetAA(UBound(vntWsName))
For intArr = 0 To UBound(vntSourceAA)
ReDim vntTarget(1 To vntTargetRows(intArr), 1 To cIntTargetCols)
For lngRow = 1 To UBound(vntSourceAA(intArr), 1)
If vntSourceAA(intArr)(lngRow, 1) = cStrSearch Then
If cIntTargetCols = 3 Then
lngCount = lngCount + 1
vntTarget(lngCount, 1) = vntSourceAA(intArr)(lngRow - 1, 1)
lngCount = lngCount - 1
End If
For lngCount2 = lngRow + 1 To UBound(vntSourceAA(intArr), 1)
If vntSourceAA(intArr)(lngCount2, 1) <> "" Then
' Debug.Print vntSourceAA(intArr)(lngCount2, 1)
lngCount = lngCount + 1
vntTarget(lngCount, cIntTargetCols - 1) _
= vntSourceAA(intArr)(lngCount2, 1)
vntTarget(lngCount, cIntTargetCols) _
= vntSourceAA(intArr)(lngCount2, 2)
lngRow = lngRow + 1
Else
Exit For
End If
Next
End If
Next
vntTargetAA(intArr) = vntTarget
lngCount = 0
Next
'***************************************
' Clean up
Erase vntTarget
Erase vntTargetRows
Erase vntSourceAA
'***************************************
' Paste each Target Array into each of this workbook's worksheet's ranges,
' which are starting at the specified cell (cStrTopCell) if no data is below,
' or else at the first empty cell found searching from the bottom.
For intArr = 0 To UBound(vntWsName)
With ThisWorkbook.Worksheets(vntWsName(intArr))
If .Cells(Rows.Count, .Range(cStrTopCell).Column + cIntTargetCols - 2) _
.End(xlUp).Row = 1 Then
' No data in column
strPasteCell = cStrTopCell
Else
' Find first empty cell searching from bottom.
strPasteCell = _
.Cells( _
.Range( _
.Cells(1, .Range(cStrTopCell).Column) _
, .Cells(Rows.Count, .Range(cStrTopCell).Column _
+ cIntTargetCols - 1)) _
.Find(What:="*", _
After:=.Range(cStrTopCell).Cells(1, 1), _
LookIn:=xlFormulas, Lookat:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious _
).Row + 1 _
, .Range(cStrTopCell).Column _
).Address
' First empty cell is above Target Top Cell Address.
If Range(strPasteCell).Row < Range(cStrTopCell).Row Then _
strPasteCell = cStrTopCell
End If
' Paste into range.
.Range(strPasteCell).Resize( _
UBound(vntTargetAA(intArr)) _
, _
UBound(vntTargetAA(intArr), 2) _
) = vntTargetAA(intArr)
End With
Next
'***************************************
' Clean up
Erase vntTargetAA
Erase vntWsName
Set objWbSource = Nothing
End Sub
'*******************************************************************************

Resources