Copy values in a column from multiple worksheets into one - arrays

The problem is the following: I have an excel file with multiple worksheets and I needed to copy the G column from every worksheet to a single new worksheet ( the columns should be next to each other or with an empty column between the columns with data). I also wanted to ask if it is possible to put the name of each worksheet above the corresponding column.
Until now, I used this code:
Sub Copy_G_Columns()
Dim ws As Worksheet, i As Long
Application.ScreenUpdating = False
On Error Resume Next
Set ws = Sheets("Gee Columns")
If Err.Number <> 0 Then
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Sheets(Sheets.Count): ActiveSheet.Name = "Gee Columns"
On Error GoTo 0
Else
Sheets("Gee Columns").Select
End If
For i = 1 To ActiveWorkbook.Sheets.Count - 1
With Sheets(i)
.Range("G1:G" & .Cells(.Rows.Count, 7).End(xlUp).Row).Copy Cells(2, i * 2 - 1)
Cells(1, i * 2 - 1) = Sheets(i).Name
End With
Next i
Application.ScreenUpdating = True
End Sub
It seems to almost work perfectly. The only problem is that in the new created sheet, the values in the columns have a #DIV/0 error. I think the problem is that the code is copying the formats and not the values.

Here is my interpretation of your code.
Option Explicit
Sub allGEE()
Dim w As Long, wsn As String, vGEEs As Variant
wsn = "Gee Columns"
For w = 1 To Worksheets.Count
With Worksheets(w)
On Error GoTo bm_NeedWorksheet
If .Name <> Worksheets(wsn).Name Then
On Error GoTo bm_Safe_Exit
vGEEs = .Range(.Cells(1, 7), .Cells(Rows.Count, 7).End(xlUp)).Value
vGEEs(1, 1) = .Name
With Worksheets(wsn).Cells(1, w * 2 - 1)
.Resize(UBound(vGEEs, 1), UBound(vGEEs, 2)) = vGEEs
End With
End If
End With
Next w
GoTo bm_Safe_Exit
bm_NeedWorksheet:
On Error GoTo 0
With Worksheets.Add(after:=Sheets(Sheets.Count))
.Name = wsn
End With
Resume
bm_Safe_Exit:
End Sub
I've retained the stagger in the destination cells. I strongly suspect that you were copying formulas across and needed the values only. Transferring values with a variant array (without the clipboard) is quicker. Direct value transfer is also possible but you wanted to put the origin worksheet name into the first cell(s).

Related

UBound Subscript out of Range Error in Excel VBA

When I run this code, it is getting a subscript out of range error in this specific line:
If i = ws_External_Test_Matrix.Cells(ws_External_Test_Matrix.Rows.Count, 1).End(xlUp).Row Then
arr_Test_Case_Rows(2, UBound(arr_Test_Case_Rows, 2)) = i ' <-- This line
End If
I unfortunately did not write this code, but my understanding is that i is supposed to be the upper bound of the array above. I've tried troubleshooting a bit and it appears that arr_Test_Case_Rows(2, UBound(arr_Test_Case_Rows, 2)) = 0 which would suggest that the Array is unallocated and therefore the error is coming from somewhere above this line. From what I have read it could be from the redim portions but I've tried ReDim arr_Test_Case_Rows(1 To 2, 1 To 1) right before the error line and while it ran, the results did not populate as expected. Anything I can do here to fix this?
Sub Populate_Test_Matrix()
Dim str_External_Test_Matrix_Name As String
Dim ws_External_Test_Matrix As Worksheet
Dim ws_TestMatrix_Tab As Worksheet
Dim ws_ItemInputs As Worksheet
Dim ws_ItemOutputs As Worksheet
Dim rng_Header_Copy_Start As Range
Dim rng_Header_Copy_End As Range
Dim rng_Copy_Start As Range
Dim rng_Copy_End As Range
Dim rng_Paste_Start As Range
Dim i As Long
Dim j As Long
Dim arr_Test_Case_Rows() As Variant
Dim boo_Empty_Row_Ind As Boolean
Dim xlx As XlXmlExportResult
Dim xmlmp As XmlMap
Dim str_Replace_String As String
Dim arr_XML_String_Holder() As Variant
Dim str_XML_Save_Name As String
Dim str_Record As String
Dim str_State As String
Dim int_Test_Case_Start_Row As Long
Application.ScreenUpdating = False
str_External_Test_Matrix_Name = Open_Workbook(ThisWorkbook.Sheets("Macro_Menu").Range("Test_Case_Matrix_Path").Value)
Set ws_External_Test_Matrix = Workbooks(str_External_Test_Matrix_Name).Sheets("MATRIX")
Set ws_TestMatrix_Tab = ThisWorkbook.Sheets("TESTMatrix")
Set ws_ItemInputs = ThisWorkbook.Sheets("ITEMINPUTS")
Set ws_ItemOutputs = ThisWorkbook.Sheets("ITEMOUTPUTS")
'Get start and end row numbers of test cases from External Test Matrix, and record into array
boo_Empty_Row_Ind = False
'Determine first row (header row) of Test Cases, to determine which row to begin looping from when
'finding Test Cases
int_Test_Case_Start_Row = ws_External_Test_Matrix.Range("A:A").Find(what:="Record", LookIn:=xlValues, LookAt:=xlWhole, After:=ws_External_Test_Matrix.Cells(ws_External_Test_Matrix.Rows.Count, 1)).Row
For i = int_Test_Case_Start_Row To ws_External_Test_Matrix.Cells(ws_External_Test_Matrix.Rows.Count, 1).End(xlUp).Row
'If 0, then row is empty
If (Application.CountA(ws_External_Test_Matrix.Cells(i, 1).EntireRow) = 0) And _
(ws_External_Test_Matrix.Cells(i, 1).EntireRow.Interior.ColorIndex = 1) Then 'If 1, then row is colored black
If boo_Empty_Row_Ind = False And (Not Not arr_Test_Case_Rows) <> 0 Then 'Array is allocated
arr_Test_Case_Rows(2, UBound(arr_Test_Case_Rows, 2)) = i - 1
End If
boo_Empty_Row_Ind = True
Else 'Row is NOT empty
'If we previously hit empty row and current row is now non-empty, we have test case to record
If boo_Empty_Row_Ind = True Then
boo_Empty_Row_Ind = False
If (Not Not arr_Test_Case_Rows) = 0 Then 'if 0, then array is unallocated
ReDim arr_Test_Case_Rows(1 To 2, 1 To 1)
Else
ReDim Preserve arr_Test_Case_Rows(1 To 2, 1 To UBound(arr_Test_Case_Rows, 2) + 1)
End If
'arr_Test_Case_Rows(1, X) = start row of test case
'arr_Test_Case_Rows(2, X) = end row of test case
arr_Test_Case_Rows(1, UBound(arr_Test_Case_Rows, 2)) = i
End If
End If
'If I = last row of loop counter
If i = ws_External_Test_Matrix.Cells(ws_External_Test_Matrix.Rows.Count, 1).End(xlUp).Row Then
arr_Test_Case_Rows(2, UBound(arr_Test_Case_Rows, 2)) = i ' <-- This line
End If
Next i
The business case context- the broader program that this module is in takes in a sheet of data and reformats it to be uploaded in another program.
The sheet is made up of one header row followed by rows of records of varying size (1 record could be 1 row, all the way up to 7). The blank rows are used to separate when one record ends and another begins.
This particular module is recording where records exist (not blank row) and the line where it breaks is referring to the final non blank row in the sheet.
In this screenshot it is 40 rows, but the actual case is 55.
Here's a slightly different approach using a Collection instead of an array:
Sub Populate_Test_Matrix()
Dim wb As Workbook, extWb As Workbook, wsExtTM As Worksheet, colRecs As Collection
Dim inRecord As Boolean, firstRecordRow, lastRow As Long
Dim rw As Range, rec, startRow As Long
'better for Open_Workbook to return a reference to the workbook, instead of its name...
Set extWb = Open_Workbook(wb.Sheets("Macro_Menu").Range("Test_Case_Matrix_Path").Value)
Set wsExtTM = extWb.Sheets("MATRIX")
firstRecordRow = Application.Match("Record", wsExtTM.Columns("A"), 0)
If IsError(firstRecordRow) Then
MsgBox "'Record' not found in ColA", vbCritical
Exit Sub
End If
Set colRecs = New Collection 'using a collection seems simpler
inRecord = False
Set rw = wsExtTM.Rows(firstRecordRow)
lastRow = wsExtTM.Cells(wsExtTM.Rows.Count, 1).End(xlUp).Row
Do While rw.Row <= lastRow
If Not RowIsEmpty(rw) Then
If Not inRecord Then
startRow = rw.Row 'save the start row
inRecord = True
End If
Else
If inRecord Then 'were we previously in a record?
colRecs.Add Array(startRow, rw.Row - 1)
inRecord = False
End If
End If
Set rw = rw.Offset(1, 0) 'next row
Loop
colRecs.Add Array(startRow, lastRow) 'close the last record
For Each rec In colRecs
Debug.Print "Start row:" & rec(0), "End row:" & rec(1)
Next rec
End Sub
'factored out a bit of logic...
Function RowIsEmpty(rw As Range) As Boolean
'using color not colorindex...
RowIsEmpty = Application.CountA(rw) = 0 And rw.Interior.Color = vbBlack
End Function

How to assign values from a 2 column array to a single column array based on a column meeting certain criteria

I need to make a macro that will gather part numbers from column A and paste them onto another sheet every 8 spaces. The catch is that I need to do this based on order codes: A11, A21, A31, B11, B21, B31, C11, C21, C31, C12, C22, C32, C13, C23, C33 (located in column B) per sheet, There are 5 sheets that are grouped as follows: Sheet 'A##' contains all codes starting with "A". Sheet 'B##' contains all codes with "B". Sheet 'C#1' contains all codes starting with C and ending with 1 and so on. This needs to be done for roughly 12000 parts. From the little knowledge I have of Excel VBA, I believe an array is the fastest way to accomplish this.
An example of what the order code looks like would be "A11", "A12", "A13" for the 3 codes needing to be sent to another sheet. I have used the wildcards symbol to limit the filtering (i.e. "A**" to represent "A13", "A23", etc.).
Below is the code I currently use to accomplish this task and with the other macros and all the looping the first run of the macro took me 1h 5 min. However, this macro will need to be run once a month and with the same workbook so I ran a second time to "refresh" the data and that took 3.5 hours. Now it won't run anymore so I have had to look for other ways to speed it up.
In the following code wb = active workbook and Sht is the sheet I want the codes onto. I wrote it this way because I am making this an excel add-in rather than just a module within the workbook.
Public Sub SetupSheetA()
Set wb = ActiveWorkbook
Set Sht = wb.Worksheets("A##")
Code = "A**"
'Grab endRow value for specific sheet designated by the order code
With wb.Worksheets("SO Hits Data Single Row")
endRow = 1 + 8 * Application.WorksheetFunction.CountIf(.Range("B4:B999999"), Code)
End With
Sht.Cells.Clear 'Clear sheet contents
'Macros
Call PartInfo
'Other macros not relevant to this question
End Sub
Public Sub PartInfo()
'***********************************************************************************************************
'Collect Part #, order code, vendor info, and WH Info
'***********************************************************************************************************
Dim j As Long, i As Long
j = Application.WorksheetFunction.CountA(wb.Sheets("SO Hits Data Single Row").Range("A1:A999999"))
With Sht
'Part #
CurrentPartRow = 2
For i = 4 To j
If Sheets("SO Hits Data Single Row").Range(Cells(i, 2).Address) Like Code Then
.Range(Cells(CurrentPartRow, 1).Address).Value = "='SO Hits Data Single Row'!" & Cells(i, 1).Address
CurrentPartRow = CurrentPartRow + 8
End If
Next i
'Order code
.Range("A3").Value = "=VLOOKUP(A2,'SO Hits Data Single Row'!$A:$B,2,FALSE)"
'Copy to Next Row
For CurrentPartRow = 10 To endRow - 7 Step 8
'Order code CopyPaste
.Range("A3").Copy Destination:=.Range(Cells(CurrentPartRow + 1, 1).Address
Next CurrentPartRow
End With
End Sub
I have tried to speed things up by saving the workbook as .xlbs which reduced the file size from 240MB to 193MB. I then deleted all the data I could get away with and removed any unnecessary formatting that further reduced the file to 163MB and then deleting the sheets the macro is pasting data onto reduced the file to 73MB.
Even with this much smaller file the macro will still hang and not respond despite running it over the entire weekend.
I also tried to filter the array using this code:
Dim arr1 As Variant, arr2 As Variant, i As Long, code As String
code = "A**" 'For any order codes containing A11, A12, A13, A21, A22, _
A23, etc
Lastrow = Sheets("SO Hits Data Single Row").Cells(Rows.Count, _
1).End(xlUp).Row
arr1 = Sheets("SO Hits Data Single Row").Range("B4:B" & Lastrow).Value
arr2 = Filter(arr1, code)
Sheets("A##").Range("a1") = arr2
But it just gives a mismatch error.
Below is a sample of the output I need to achieve.
If you have Excel 2019 or Excel 365, then you can use the built-in SORT and FILTER functions to greatly simplify things:
Public Function PartsToSheet(OrderPrefix AS String) AS Boolean
PartsToSheet = False
On Error GoTo FuncErr 'Return False if there is an error
Dim calcTMP As xlCalculation
calcTMP = Application.Calculation
'Only Calculate Formulae when we explicitly say to
Application.Calculation = xlCalculationManual
Dim wsSource AS Worksheet, wsDestination AS Worksheet
Dim lParts AS Long, lRecords AS Long
Dim adTable AS String, adOrders AS String
Set wsSource = ThisWorkbook.Worksheets("SO Hits Data Single Row")
Set wsDestination = ThisWorkbook.Worksheets(OrderPrefix & "##")
'Prepare the Destination
With wsDestination
'Deleting Rows & Columns frees up the Used Range, freeing more memory than Clear does
.Range(.Cells(1, 1), .Range(.Rows.Count, 1)).EntireRow.Delete
.Range(.Cells(1, 1), .Range(1, .Columns.Count)).EntireColumn.Delete
End With
lParts = Application.CountA(wsSource.Columns(1))
lRecords = Application.CountIf(wsSource.Columns(2), OrderPrefix & "*")
adTable = wsSource.Range(wsSource.Cells(1, 1),wsSource.Cells(lParts, 2)).Address(True, True, xlA1, True)
adOrders = wsSource.Range(wsSource.Cells(1, 2),wsSource.Cells(lParts, 2)).Address(True, True, xlA1, True)
If lRecords > 0 Then 'If there are Order Codes for this Sheet
wsDestination.Range(wsDestination.Cells(2, 1), wsDestination.Cells(8 * lRecords - 6)).Formula = _
"=IF(MOD(ROW()+6,8)>0, """", INDEX(SORT(" & _
"FILTER(" & adTable & ", LEFT(" & adOrders & ", 1)=""" & OrderPrefix & """)" & _
", 2), (ROW()+6)/8, 1))"
wsDestination.Columns(1).Calculate 'Explicitly calculate formulae
wsDestination.Range(wsDestination.Cells(2, 1), wsDestination.Cells(8 * lRecords - 6)).Value = _
wsDestination.Range(wsDestination.Cells(2, 1), wsDestination.Cells(8 * lRecords - 6)).Value
End If
PartsToSheet = True 'Success!
FuncErr:
On Error GoTo -1 'Clear any errors in the handler
Application.Calculation = calcTMP
End Function
Basically, we fill the first column of the destination sheet with a function that will be blank for 7 lines (IF(MOD(ROW()+6,8)>0,), then provide the next entry (INDEX(.., (ROW()+6)/8, 1)) in an array that we get by FILTERing for the Prefix, and SORTing on the Order Code.
Then we "flatten" the result by converting it from dynamic formulae into static values.
So, I have found that an array was in fact the best way to approach this. However, The file size was clearly a major issue, and I found it was due to blank cells being included in the current selection. Once I fixed that the macro ran quicker but still took too long. I ended up writing code to save the data to an array and then filter it later in a similar fashion to the following.
Sub Example()
Dim arr1 As Variant, arr2(10000) As Variant, i As Long, j As Long, k As Long, Filter As String
Application.ScreenUpdating = False 'Freeze screen while macro runs
Application.EnableEvents = False 'Disable popups
Application.Calculation = xlManual 'Disable Sheet calcs
Filter = "A**"
arr1 = ActiveWorkbook.Worksheets("Sheet1").Range("A4:B12000").Value
j= Application.WorksheetFunction.CountA(wb.Sheets("SO Hits Data Single Row").Range("A1:A20000"))
For i = 1 To j
If arr1(i, 2) Like Filter Then
arr2(k) = arr1(i, 1)
arr2(k + 1) = ""
arr2(k + 2) = ""
arr2(k + 3) = ""
arr2(k + 4) = ""
arr2(k + 5) = ""
arr2(k + 6) = ""
arr2(k + 7) = ""
k = k + 8 'This was so I could adjust for the blank spaces I needed between each value in the array
End If
Next i
Application.ScreenUpdating = True 'Unfreeze screen
Application.Calculation = xlAutomatic 'Enable Sheet calcs
Application.EnableEvents = True 'Enable popups
End Sub
The above code is a little more specific to my situation but below is a more general form for any future viewers.
Sub Example()
Dim arr1 As Variant, arr2(10000) As Variant, i As Long, j As Long, k As Long, Filter As String
Application.ScreenUpdating = False 'Freeze screen while macro runs
Application.EnableEvents = False 'Disable popups
Application.Calculation = xlManual 'Disable Sheet calcs
Filter = "A**" 'This is where you would put your filter instead of "A**"
arr1 = ActiveWorkbook.Worksheets("Sheet1").Range("A4:B12000").Value
j= Application.WorksheetFunction.CountA(wb.Sheets("SO Hits Data Single Row").Range("A1:A20000"))
For i = 1 To j
If arr1(i, 2) Like Filter Then
arr2(k) = arr1(i, 1)
End If
Next i
Application.ScreenUpdating = True 'Unfreeze screen
Application.Calculation = xlAutomatic 'Enable Sheet calcs
Application.EnableEvents = True 'Enable popups
End Sub

Copy Transpose Paste Vertically Breaking on Blanks

I am new to VBA and coding in general and I am being tasked with some coding that is proving difficult. I am trying to copy/transpose/paste values from a two-column PivotTable and I need it to paste vertically on another sheet and break on blanks. (see image) I need to copy each group in the PivotTable then transpose paste values vertically on a new worksheet. I believe I need to count populated rows (using an array?) until I get to a blank row then paste the group. I can picture what I need to do but all my coding attempts are way off. Except for the copy/paste, I have no clue how to code this. I cannot figure out how to capture each group of populated rows to be pasted.
' Copy a vertical range (on "FQNID_Sites" sheet) and paste to a horizontal range in column B (next blank row on "BH_FH" sheet)
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("FQNID_Sites")
Dim destinationSheet As Worksheet
Set destinationSheet = ThisWorkbook.Worksheets("BH_FH")
Dim cellToPasteTo As Range
' Need to loop through each group breaking on each siteNFID in column D (or break on blanks in column E?)
Set rng = Range("$D$2:$E$" & ActiveSheet.UsedRange.Rows.Count)
For Each cell In rng
Set cellToPasteTo = destinationSheet.Cells(destinationSheet.Rows.Count, "B").End(xlUp).Offset(1, 0)
If cell.Value = "" And Not IsNull(copyStart) Then
copyEnd = cell.Offset(-1, 0).Address
ElseIf cell.Value = "" Then
copyStart = cell.Offset(0, -1).Address
End If
If Not IsNull(copyStart) And Not IsNull(copyEnd) Then
sourceSheet.Range(copyStart & ":" & copyEnd).Select
Selection.Copy
cellToPasteTo.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Transpose:=True
End If
Next cell
Application.CutCopyMode = False
I need it to break on each siteNFID/FQNID then paste values for each group vertically in column B on the BH_FH worksheet.
Example of the input and expected output format
This code will work. Tested on similar data structure. I used the code sheet name in the code `Sheet1'. Change as needed.
Option Explicit
Sub runTranspose()
With Sheet1
Dim lastRow As Long
lastRow = .Cells(.Rows.Count, 4).End(xlUp).Row
'load range starts to transpose
Dim i As Long
For i = 2 To lastRow
If Len(.Cells(i, 5)) = 0 Then
Dim startTranspose As Range
If startTranspose Is Nothing Then
Set startTranspose = .Cells(i, 5)
Else
Set startTranspose = Union(startTranspose, .Cells(i, 5))
End If
End If
Next
Dim c As Range
For Each c In startTranspose
transposeData c
Next
End With
End Sub
Sub transposeData(r As Range)
With Sheet1
Dim nextRow As Long
nextRow = .Cells(.Rows.Count, 8).End(xlUp).Row + 1
Dim fullRange As Range
Set fullRange = Range(r.Offset(1, -1), r.Offset(1).End(xlDown))
Dim arr As Variant
arr = fullRange.Value
.Cells(nextRow,7).Value = r.offset(-1).Value 'to add label
.Cells(nextRow, 8).Resize(2, UBound(arr)).Value = Application.Transpose(arr)
End With
End Sub

Using an array for unique copy from multiple sheets / VBA

I have been working on a macro that summarizes the data from multiple sheets in my workbook. In order to know which columns to use in my summary sheet I need to first extract all the unique values from the first column in my sheets.
The idea is that it will loop through the sheets and define a range, then it will loop through each cell in the range, check if the value of that cell is already in the array and if not copy and paste it and add it to the array.
Unfortunately I get an the error "Index outside of valid Area" for the line that is supposed to add the cell value to the array.
ReDim Preserve uniqueVal(1 To UBound(uniqueVal) + 1) As Variant
I took that specific code from the question https://superuser.com/questions/808798/excel-vba-adding-an-element-to-the-end-of-an-array .
Here is the entire code for reference.
Private Sub CommandButton24_Click()
Dim xSheet As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim copyRng As Range
Dim destRng As Range
Dim cRange As Range
Dim c As Range
Dim uniqueVal() As Variant
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the summary worksheet if it exists.
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Summary").Delete
On Error GoTo 0
Application.DisplayAlerts = True
' Add a worksheet with the name "Summary"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "Summary"
Set destRng = DestSh.Range("A1")
'Define inital array values
uniqueVal = Array("Account by Type", "Total")
' Loop through all worksheets and copy the data to the
' summary worksheet.
For Each xSheet In ActiveWorkbook.Worksheets
If InStr(1, xSheet.Name, "ACCOUNT") And xSheet.Range("B1") <> "No Summary Available" Then _
Set copyRng = xSheet.Range("A:A")
For Each c In copyRng.SpecialCells(xlCellTypeVisible)
If Len(c) <> 0 And Not ISIN(c, uniqueVal) Then _
'Copy to destination Range
c.Copy destRng
'move destination Range
Set destRng = destRng.Offset(0, 1)
'change / adjust the size of array
ReDim Preserve uniqueVal(1 To UBound(uniqueVal) + 1) As Variant
'add value on the end of the array
uniqueVal(UBound(uniqueVal)) = c.Value
End If
Next c
End If
Next xSheet
ExitTheSub:
Application.Goto DestSh.Cells(1)
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Per default, arrays in Excel VBA start with the index 0, not the index 1. You can test this by checking your arrays contents: your first string "Account by Type" should be on uniqueval(0) rather than on uniqueval(1).
Two ways to solve this:
add Option Base 1 to the top of your module or
change ReDim Preserve uniqueval(1 To UBound(uniqueval) + 1) to ReDim Preserve uniqueval(0 To UBound(uniqueval) + 1)
It's up to you which one you chose, but imo the latter is cleaner, since you don't have to fiddle with array options on module level.
As I see it, you're not actually using the arrays' contents yet. If you do later on, just loop For i = LBound(uniqueval) To UBound(uniqueval) - in which case it is irrelevant with what option you went.
On the first loop uniqueVal has no Ubound. That's why it fails. So, you should first Redim it as Redim uniqueVal(1 To 1), then write to the Ubound and increase the size thereafter. That would always leave you with a blank element at the top which you can remove at the end.
The better (because it runs faster) is to Dim uniqueVal to a possible max number, then set the current index with a counter, like i = i + 1, and do a Redim Preserve uniqueVal(i) at the end, thereby cutting off all unused elements.
The underscore at the end of a line of code means that the line is continued, logically, in the next line. For example,
If 1 <> 2 Then _
Debug.Print "All is well"
This is the same as If 1 <> 2 Then Debug.Print "All is well"
Observe, however, that there is no End If. If there were more than one command to follow the Then you must use End If, for example,
If 1 <> 2 Then
Debug.Print "All is well"
A = 3
End If
Here, everything between If and End If will only be executed if 1 <> 2. This is the case with If Len(c) <> 0 And Not ISIN(c, uniqueVal) Then _. Once the error of the UBound is cured this one will stop your code from running. Remove the underscore following the Then.

Take a list on one sheet then find appropriate tab and copy contents to next available row in another sheet

I have been wrestling with this for a day or so and am stumped.
Here is what I want to do:
I have a sheet with a complete list of the tab names in column A. Call this Total Tabs.
I have another sheet called "Reps No Longer Here". This is the target sheet where the contents of the individual tabs in the list are to be copied to.
I can put the names into an array (2D) and access the individual members, but I need to be able to compare the list name in the array to the tab names to find the correct tab. Once found, copy ALL the contents of that tab to "Reps No Longer Here" (next available row).
When it is finished the sheet "Reps No Longer Here" should be a complete list of all of the tabs listed in the array and sorted by the rep name.
How the heck do I do this? I'm really having a problem comparing the tabs to the list array and then copying all of the non-empty rows to the "Reps No Longer Sheet"
I appreciate all the help...
Jeff
ADDED:
Here is what I have so far, but it just isn't working:
Private Sub Combinedata()
Dim ws As Worksheet
Dim wsMain As Worksheet
Dim DataRng As Range
Dim Rw As Long
Dim Cnt As Integer
Dim ar As Variant
Dim Last As Integer
Cnt = 1
Set ws = Worksheets("Total Tabs")
Set wsMain = Worksheets("Reps No Longer Here")
wsMain.Cells.Clear
ar = ws.Range("A1", Range("A" & Rows.Count).End(xlUp))
Last = 1
For Each sh In ActiveWorkbook.Worksheets
For Each ArrayElement In ar 'Check if worksheet name is found in array
If ws.name <> wsMain.name Then
If Cnt = 1 Then
Set DataRng = ws.Cells(2, 1).CurrentRegion
DataRng.Copy wsMain.Cells(Cnt, 1)
Else: Rw = wsMain.Cells(Rows.Count, 1).End(xlUp).Row + 1
'don't copy header rows
DataRng.Offset(1, 0).Resize(DataRng.Rows.Count - 1, _
DataRng.Columns.Count).Copy ActiveSheet.Cells(Rw, 1)
End If
End If
Cnt = Cnt + 1
Last = Last + 1
Next ArrayElement
Next sh
End Sub
UPDATE - 7/3/14
This is the modified code. I'll highlight the line that is giving syntax error.
Sub CopyFrom2To1()
Dim Source As Range, Destination As Range
Dim i As Long, j As Long
Dim arArray As Variant
Set Source = Worksheets("Raw Data").Range("A1:N1")
Set Dest = Worksheets("Reps No Longer Here").Range("A1:N1")
arArray = Sheets("Total Tabs").Range("A1", Range("A" & Rows.Count).End(xlUp))
For i = 1 To 100
For j = 1 To 100
If Sheets(j).name = arArray(i, 1) Then
Source.Range("A" & j).Range("A" & j & ":N" & j).Copy ' A1:Z1 relative to A5 for e.g.
***Dest.Range("A" & i ":N" & i).Paste***
Exit For
End If
Next j
Next i
End Sub
The solution to a very similar problem was posted here yesterday by me. Have a look at the main loop in the code:
Sub CopyFrom2TO1()
Dim Source as Range, Destination as Range
Dim i as long, j as long
Set Source = Worksheets("Sheet1").Range("A1")
Set Dest = Worksheets("Sheet2").Range("A2")
for i = 1 to 100
for j = 1 to 100
if Dest.Cells(j,1) = Source.Cells(i,1) then
Source.Range("A" & j).Range("A1:Z1").Copy ' A1:Z1 relative to A5 for e.g.
Dest.Range("A"&i).Paste
Exit For
end if
next j
next i
End Sub
This would need slight modifications for your purpose, but it essentially does the same thing. Compares a column to a another column and copies wherever a match takes places.
Unable to find how to code: If Cell Value Equals Any of the Values in a Range

Resources