I’ve a spreadsheet that will have a different number of rows each day.
I am trying to divide that number of rows by 6 then copy the info into six different sheets within the same workbook.
For example – say the original sheet has 3000 rows. 3000 rows divided by 6 (500), copied into six different sheets or maybe there are 2475 rows, now dividing it by 6 and trying to keep the number of record split between sheets approximately the same (keeping the sheet with the original 3000 or 2475 rows as is) within the same workbook.
I have code that is creating 6 additional sheets but the records are not being copied to these sheets.
Option Explicit
Public Sub CopyLines()
Dim firstRow As Long
Dim lastRow As Long
Dim i As Long
Dim index As Long
Dim strsheetName As String
Dim sourceSheet As Worksheet
Dim strWorkbookName As Workbook
Sheets.Add
Sheets.Add
Sheets.Add
Sheets.Add
Sheets.Add
Sheets.Add
Set sourceSheet = Workbooks(strWorkbookName).Worksheets(strsheetName)
firstRow = sourceSheet.UsedRange.Row
lastRow = sourceSheet.UsedRange.Rows.Count + firstRow - 1
index = 1
For i = firstRow To lastRow
sourceSheet.Rows(i).Copy
Select Case index Mod 6
Case 0:
strsheetName = "Sheet1"
Case 1:
strsheetName = "Sheet2"
Case 2:
strsheetName = "Sheet3"
Case 3:
strsheetName = "Sheet4"
Case 4:
strsheetName = "Sheet5"
Case 5:
strsheetName = "Sheet6"
End Select
Worksheets(strsheetName).Cells((index / 6) + 1, 1).Paste
index = index + 1
Next i
End Sub
FEW THINGS:
Do not create sheets in the begining. Create them in a loop if required. This way you will not end up with blank sheets if there are only say 3 rows of data. Create them in a loop.
Also the code below assumes that you do not have Sheet1-6 beforehand. Else you will get an error at newSht.Name = "Sheet" & i
Avoid the use of UsedRange to find the last row. You may want to see see Finding last used cell in Excel with VBA
CODE:
I have commneted the code. You should not have a problem understanding the code but if you do then simply post back. Is this what you are trying?
Option Explicit
'~~> Set max sheets required
Const NumberOfSheetsRequired As Long = 6
Public Sub CopyLines()
Dim wb As Workbook
Dim ws As Worksheet, newSht As Worksheet
Dim lastRow As Long
Dim StartRow As Long, EndRow As Long
Dim i As Long
Dim NumberOfRecordToCopy As Long
Dim strWorkbookName as String
'~~> Change the name as applicable
strWorkbookName = "TMG JULY 2020 RENTAL.xlsx"
Set wb = Workbooks(strWorkbookName)
Set ws = wb.Sheets("MainSheet")
With ws
If Not Application.WorksheetFunction.CountA(.Cells) = 0 Then
'~~> Find last row
lastRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
'~~> Get the number of records to copy
NumberOfRecordToCopy = lastRow / NumberOfSheetsRequired
'~~> Set your start and end row
StartRow = 1
EndRow = StartRow + NumberOfRecordToCopy
'~~> Create relevant sheet
For i = 1 To NumberOfSheetsRequired
'~~> Add new sheet
Set newSht = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
newSht.Name = "Sheet" & i
'~~> Copy the relevant rows
ws.Range(StartRow & ":" & EndRow).Copy newSht.Rows(1)
'~~> Set new start and end row
StartRow = EndRow + 1
EndRow = StartRow + NumberOfRecordToCopy
'~~> If start row is greater than last row then exit loop.
'~~> No point creating blank sheets
If StartRow > lastRow Then Exit For
Next i
End If
End With
Application.CutCopyMode = False
End Sub
Your code creates 6 sheets before it does anything with the data, which might be wasteful.
Also, once these sheets are created, there are no guarantee that they will have the names Sheet1, Sheet2, etc. These names might have already been used. That is why you should always check if the destination sheet exists before attempting to create them.
Option Explicit
Public Sub CopyLines()
Dim firstRow As Long
Dim lastRow As Long
Dim i As Long
Dim index As Long
Dim strSheetName As String
Dim sourceSheet As Worksheet
Dim strWorkbookName As String
'assume the current workbook is the starting point
strWorkbookName = ActiveWorkbook.Name
'assume that the first sheet contains all the rows
strSheetName = ActiveWorkbook.Sheets(1).Name
Set sourceSheet = Workbooks(strWorkbookName).Worksheets(strSheetName)
firstRow = sourceSheet.UsedRange.Row
lastRow = sourceSheet.UsedRange.Rows.Count + firstRow - 1
index = 1
For i = firstRow To lastRow
sourceSheet.Rows(i).Copy
Select Case index Mod 6
Case 0:
strSheetName = "Sheet1"
Case 1:
strSheetName = "Sheet2"
Case 2:
strSheetName = "Sheet3"
Case 3:
strSheetName = "Sheet4"
Case 4:
strSheetName = "Sheet5"
Case 5:
strSheetName = "Sheet6"
End Select
'check if the destination sheet exists
If Not Evaluate("ISREF('" & strSheetName & "'!A1)") Then
'if it does not, then create it
Sheets.Add
'and rename it to the proper destination name
ActiveSheet.Name = strSheetName
End If
'now paste the copied cells using PasteSpecial
Worksheets(strSheetName).Cells(Int(index / 6) + 1, 1).PasteSpecial
'advance to the next row
index = index + 1
'prevent Excel from freezing up, by calling DoEvents to handle
'screen redraw, mouse events, keyboard, etc.
DoEvents
Next i
End Sub
Try the next code, please. It uses arrays and array slices and it should be very fast:
Sub testSplitRowsOnSixSheets()
Dim sh As Worksheet, lastRow As Long, lastCol As Long, arrRows As Variant, wb As Workbook
Dim arr As Variant, slice As Variant, SplCount As Long, shNew As Worksheet
Dim startSlice As Long, endSlice As Long, i As Long, Cols As String, k As Long
Const shtsNo As Long = 6 'sheets number to split the range
Set wb = ActiveWorkbook 'or Workbooks("My Workbook")
Set sh = wb.ActiveSheet 'or wb.Sheets("My Sheet")
lastRow = sh.Range("A" & rows.count).End(xlUp).row 'last row of the sheet to be processed
lastCol = sh.UsedRange.Columns.count 'last column of the sheet to be processed
arr = sh.Range(sh.Range("A2"), sh.cells(lastRow, lastCol)) 'put the range in an array
SplCount = WorksheetFunction.Ceiling_Math(UBound(arr) / shtsNo) 'calculate the number of rows for each sheet
Cols = "A:" & Split(cells(1, lastCol).Address, "$")(1) 'determine the letter of the last column
clearSheets wb 'delete previous sheets named as "Sheet_" & k
For i = 1 To UBound(arr) Step SplCount 'iterate through the array elements number
startSlice = i: endSlice = i + SplCount - 1 'set the rows number to be sliced
'create the slice aray:
arrRows = Application.Index(arr, Evaluate("row(" & startSlice & ":" & endSlice & ")"), _
Evaluate("COLUMN(" & Cols & ")"))
'insert a new sheet at the end of the workbook:
Set shNew = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.count))
shNew.Name = "Sheet_" & k: k = k + 1 'name the newly created sheet
If UBound(arr) - i < SplCount Then SplCount = UBound(arr) - i + 1 'set the number of rows having data
'for the last slice
shNew.Range("A2").Resize(SplCount, lastCol).value = arrRows 'drop the slice array at once
Next i
End Sub
Sub clearSheets(wb As Workbook)
Dim ws As Worksheet
For Each ws In wb.Worksheets
If left(ws.Name, 7) Like "Sheet_#" Then
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End If
Next
End Sub
Try this following code. It streams through data and adds sheets dynamically, renames them according to the row# , copies the headers from the first row and the data block needed.
Public Sub DistributeData()
Const n_sheets As Long = 6
Dim n_rows_all As Long, n_cols As Long, i As Long
Dim r_data As Range, r_src As Range, r_dst As Range
' First data cell is on row 2
Set r_data = Sheet1.Range("A2")
' Count rows and columns starting from A2
n_rows_all = Range(r_data, r_data.End(xlDown)).Rows.Count
n_cols = Range(r_data, r_data.End(xlToRight)).Columns.Count
Dim n_rows As Long, ws As Worksheet
Dim n_data As Long
n_data = n_rows_all
' Get last worksheet
Set ws = ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets().Count)
Do While n_data > 0
' Figure row count to copy
n_rows = WorksheetFunction.Min(WorksheetFunction.Ceiling_Math(n_rows_all / n_sheets), n_data)
' Add new worksheet after last one
Set ws = ActiveWorkbook.Worksheets.Add(, ws, , XlSheetType.xlWorksheet)
ws.Name = CStr(n_rows_all - n_data + 1) & "-" & CStr(n_rows_all - n_data + n_rows)
' Copy Headers
ws.Range("A1").Resize(1, n_cols).Value = _
Sheet1.Range("A1").Resize(1, n_cols).Value
' Skip rows from source sheet
Set r_src = r_data.Offset(n_rows_all - n_data, 0).Resize(n_rows, n_cols)
' Destination starts from row 2
Set r_dst = ws.Range("A2").Resize(n_rows, n_cols)
' This copies the entire block of data
' (no need for Copy/Paste which is slow and a memory hog)
r_dst.Value = r_src.Value
' Update remaining row count to be copied
n_data = n_data - n_rows
' Go to next sheet, or wrap around to first new sheet
Loop
End Sub
Do not use Copy/Paste as it is slow and buggy. It is always a good idea to directly write from cell to cell the values. You can do that for an entire table of cells (multiple rows and columns) with one statement like in the example below:
ws_dst.Range("A2").Resize(n_rows,n_cols).Value = _
ws_src.Range("G2").Resize(n_rows,n_cols).Value
Sub split()
On Error Resume Next
Application.DisplayAlerts = False
Dim aws As String
Dim ws As Worksheet
Dim wb As Workbook
Dim sname()
sname = Array("one", "two", "three", "four", "five", "six")
aws = ActiveSheet.Name
For Each ws In Worksheets
If ws.Name = "one" Then ws.Delete
If ws.Name = "two" Then ws.Delete
If ws.Name = "three" Then ws.Delete
If ws.Name = "four" Then ws.Delete
If ws.Name = "five" Then ws.Delete
If ws.Name = "six" Then ws.Delete
Next ws
lr = (Range("A" & Rows.Count).End(xlUp).Row) - 1
rec = Round((lr / 6), 0)
Set ws = ActiveSheet
f = 1
t = rec + 1
i = 1
While i <= 6
Sheets.Add.Name = sname(i - 1)
Sheets(aws).Select
If i = 6 Then
Range("A" & (f + 1), "A" & (lr + 1)).Select
Else
Range("A" & (f + 1), "A" & t).Select
End If
Selection.Copy
Sheets(sname(i - 1)).Select
Range("A2").Select
ActiveSheet.Paste
Cells(1, 1).Value = ws.Range("A1").Value
f = f + rec
t = t + rec
i = i + 1
Wend
End Sub
Related
I am fairly new to VBA and have made the following from combining other users code. The code works and successfully copies rows from one sheet into an index of sheets in another workbook if they contain the target sheet's name. However, it runs very slowly do to looping through multiple activate and select functions. I can't work out how to speed it up and not use activate or select, while still making the code work.
Sub Copy_Rows_Sample()
Dim wb1 As Workbook, wb2 As Workbook
Set wb1 = Workbooks.Open("C:\Sample1.xslx")
Set wb2 = Workbooks.Open("C:\Sample2.xslx")
Dim Page1 As Worksheet
Set Page1 = wb2.Worksheets("Page1")
wb1.Worksheets(1).Activate
Excel.Application.DisplayAlerts = False
Dim wksh As Excel.Worksheet
Dim jIndex As Integer
For jIndex = 1 To wb1.Worksheets.Count
Set wksh = wb1.Worksheets(jIndex)
With wksh
Dim ran As Range
For Each ran In Range("A3")
ran = StrConv(ran.Text, vbProperCase)
Next
Z = Split(Range("A3").Value, ",")(0)
ActiveSheet.name = Z
Dim Y As Variant
Set Y = ActiveSheet
Page1.Activate
Dim xRow&, NextRow&, LastRow&
LastRow = Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
For xRow = 1 To LastRow
NextRow = Y.Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row + 2
If WorksheetFunction.CountIf(Rows(xRow), "*" & Z & "*") > 0 Then
Rows(xRow).Copy Y.Rows(NextRow)
NextRow = NextRow + 1
End If
Next xRow
Y.Activate
wb1.Worksheets(ActiveSheet.Index Mod Worksheets.Count + 1).Select
End With
Next jIndex
Excel.Application.DisplayAlerts = True
End Sub
I have two workbooks that have different column structures. I want to compare names from the "studentMaster" sheet and "wpl" sheet, if the name matched in "wpl" then copy the row value and insert it into the "studentMaster" sheet.
My code:
Sub findWPLMarks()
'Declare the workbook
Dim studMaster As Workbook, WPL_Result As Workbook
'Destination sheets
Dim MstdataSh As Worksheet, wplSh As Worksheet
'Declare the variables
Dim i As Long, j As Long, foundrow As Long, rowInc As Long, colInc As Long
Dim lastrow1 As Long, lastrow2 As Long, lastcol As Long
Dim mstFName As String, WPLFName As String
Dim WPLfldName As String, folderPath() As String
'Declare the path value
mstFName = Range("C15").Value
WPLFName = Range("B9").Value
'Split the file name path
folderPath = Split(WPLFName, Application.PathSeparator)
WPLfldName = folderPath(4)
'Set Workbook
Set studMaster = Workbooks.Open(mstFName)
Set WPL_Result = Workbooks.Open(WPLFName)
'Master sheet
Set MstdataSh = studMaster.Sheets("StudentDetails") 'ws2
'Destination sheet
Set wplSh = WPL_Result.Sheets("WPL") 'ws1
Application.ScreenUpdating = False
lastrow1 = MstdataSh.Cells(MstdataSh.Rows.Count, "A").End(xlUp).Row
lastrow2 = wplSh.Cells(wplSh.Rows.Count, "A").End(xlUp).Row
lastcol = MstdataSh.Cells(6, MstdataSh.Columns.Count).End(xlToLeft).Column
Debug.Print (lastcol)
rowInc = 7
For i = 1 To lastrow1
colInc = 4
On Error Resume Next
foundrow = wplSh.Range("A2:A" & lastrow2).Find(MstdataSh.Cells(i, 4).Value).Row
'foundrow = MstdataSh.Range("D7:D" & lastrow1).Find(wplSh.Cells(i, 1).Value).Row
If Err.Number = 91 Then
' ws3.Cells(i, 1) = ws1.Cells(i, 1)
'MstdataSh.Cells(i, 1) = wplSh.Cells(i, 1)
'Debug.Print wplSh.Cells(i, 1)
Else
For j = 1 To lastrow2
'ws3.Cells(i, j) = ws2.Cells(foundrow, j)
MstdataSh.Cells(foundrow, colInc) = wplSh.Cells(foundrow, j)
colInc = colInc + 3
Next j
End If
rowInc = rowInc + 1
Next i
'Close workbook
studMaster.Close savechanges:=True
WPL_Result.Close savechanges:=True
'ActiveWorkbook.Close savechanges:=False
Application.ScreenUpdating = True
End Sub
If the Assessment Date is different for the duplicate students' in the "wpl" sheet then need to select the best value for each column for that student.
Could you help me insert the row into the "studentMaster" sheet?
I have an Excel sheet with 50,000+ rows of data from A:N. I have a Master Data Sheet that has a query in the BackupData worksheet. I currently copy that data and paste as values into the Backup worksheet. With the headers:
ID
Vendor #
Name
Customer #
Customer
Invoice #
Date
Item#
Item Description
Qty
B/C
Lbs
Amt
Amt#2
I am trying to loop through all of these rows and copy the range of cells A:N until the first value change in Column A, the first different ID #.
I then need to paste the selected range into a new workbook.
Basically, I want to do the opposite of consolidating.
Sub inserting()
Dim wsBData, wsExport, wsCoverSht, wsBackup As Worksheet
Dim wbAllRebates, wbSingle As Workbook
Set wbAllRebates = ActiveWorkbook
Set wsBData = wbAllRebates.Sheets("BackupData")
Set wsBackup = wbAllRebates.Sheets("Backup")
Dim rID, rTopRow As Range
Dim i As Long
Dim Counter As Integer
i = 3
Set rTopRow = Rows(1)
Set rID = wsBackup.Range("A1")
wsBData.Cells.Copy
wsBackup.Cells.PasteSpecial Paste:=xlPasteValues
Counter = 0
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Do
If rID.Offset(i).Value <> rID.Offset(i - 1).Value Then
Rows(rID.Offset(i).Row).Insert shift:=xlDown
Call SubTotals(rID.Offset(i), rTopRow)
i = i + 1
Set rTopRow = Rows(rID.Offset(i).Row)
End If
Exit Do
Loop
MsgBox i
End Sub
Sub SubTotals(rID As Range, firstRow As Range)
rID.Value = "Total"
rID.Offset(, 9).Value = Application.WorksheetFunction.Sum(Range(firstRow.Cells(1, 10).Address & ":" & rID.Offset(-1, 1).Address))
End Sub
Try
Option Explicit
Sub SeparateWB()
Dim wsBData As Worksheet, wsBackup As Worksheet, wb As Workbook
Dim wbAllRebates As Workbook, rngHeader As Range
Dim i As Long, n As Long, LastRow As Long, StartRow As Long
Set wbAllRebates = ActiveWorkbook
With wbAllRebates
Set wsBData = .Sheets("BackupData")
Set wsBackup = .Sheets("Backup")
End With
wsBData.Cells.Copy
wsBackup.Cells.PasteSpecial Paste:=xlPasteValues
StartRow = 2
Application.ScreenUpdating = False
With wsBackup
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rngHeader = .Range("A1:N1")
For i = 2 To LastRow
' change ID next row
If .Cells(i, "A") <> .Cells(i + 1, "A") Then
' create new workbook
Set wb = Workbooks.Add(1)
rngHeader.Copy wb.Sheets(1).Range("A1")
.Range("A" & StartRow & ":N" & i).Copy wb.Sheets(1).Range("A2")
wb.SaveAs .Cells(i, "A") & ".xlsx"
wb.Close False
' move to next
StartRow = i + 1
n = n + 1
End If
Next
End With
Application.ScreenUpdating = True
MsgBox n & " workbooks created"
End Sub
I have a macro that copies rows from a Sheet named "Template" and pastes them onto the Active Sheet in the next blank row.
However this macro only works when the grouped cells on the Active Sheet are expanded.
If the grouped cells are collapsed, then the macro replaces a previous collapsed group.
I have done some reading and discovered that using a different method to calculate the last row i.e. the MergeArea property would work with collapsed groups but just sure how to apply it.
How could I achieve this with the current code?
This is my code:
Sub Paste_New_Product_from_Template()
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Dim LRow As Long, i As Long
Dim StartNumber As Long
Dim varString As String
'~~> This is your input sheet
Set copySheet = ThisWorkbook.Worksheets("Template")
'~~> Variable
varString = copySheet.Cells(2, 2).Value2
'~~> Change this to the relevant sheet
Set pasteSheet = ThisWorkbook.ActiveSheet
'~~> Initialize the start number
StartNumber = 1
With pasteSheet
'~~> Find the last cell to write to
If Application.WorksheetFunction.CountA(.Cells) = 0 Then
LRow = 2
Else
LRow = .Range("A" & .Rows.Count).End(xlUp).Row + 1
'~~> Find the previous number
For i = LRow To 1 Step -1
If .Cells(i, 2).Value2 = varString Then
StartNumber = .Cells(i, 6).Value2 + 1
Exit For
End If
Next i
End If
copySheet.Range("2:" & copySheet.Cells(Rows.Count, 1).End(xlUp).Row).Copy
.Rows(LRow).PasteSpecial Paste:=xlPasteAll
'~~> Set the start number
.Cells(LRow, 6).Value = StartNumber
'~~> Format the number
.Cells(LRow, 6).Value = "'" & Format(StartNumber, "000")
End With
End Sub
Here is the code that uses the MergeArea procedure:
Private Function RowIsEmpty(WSh As Worksheet, Row As Long, StartColumnNumber As Integer, EndColumnNuber As Integer) As Boolean
Dim j As Integer
RowIsEmpty = True
For j = StartColumnNumber To EndColumnNuber
If (WSh.Cells(WSh.Cells(Row, j).MergeArea.Row, WSh.Cells(Row, j).MergeArea.Column) <> "") Then
RowIsEmpty = False
Exit For 'One of columns isn't empty
End If
Next j
End Function
Private Function CalcLastRowNumber(WSh As Worksheet, StartColumnNumber As Integer, EndColumnNuber As Integer) As Long
Dim i As Long
Dim j As Integer
Dim Result As Long
Dim Found As Boolean
Result = 1
For i = 1 To Rows.Count
If RowIsEmpty(WSh, i, StartColumnNumber, EndColumnNuber) And _
RowIsEmpty(WSh, i + 1, StartColumnNumber, EndColumnNuber) And _
RowIsEmpty(WSh, i + 2, StartColumnNumber, EndColumnNuber) Then
'Stop searching
Exit For 'All Columns are empty for current row and for next 2 rows
End If
Result = i
Next i
CalcLastRowNumber = Result
End Function
Sub New_Reviss_Order()
I have a spreadsheet with 20+ worksheets listing servers. I am trying to format each sheet to pull only the first four columns of data, while preserving the original data. I am inserting 6 columns on the left, creating column headings, copying the first four rows of data (with starting name of "SERV-"), then putting the name of the worksheet in the 5th column. I got the code to work fine if ran in one sheet. I am trying to put it in a loop, but it isn't working. It is inserting the columns and headers in the first worksheet only.
Once I have this loop working, I want to create a summary tab where it pulls the data from these first five rows of each sheet into the summary tab. This should be easy, but I haven't gotten to that point in the code yet.
This is the code I have so far:
'PhaseOne of test code
Sub PhaseOne()
Dim ws As Worksheet
Dim lngRow As Long
Dim lngCount As Long
lngRow = 8
For Each ws In Worksheets
'(2) Remove blank rows (WORKS)
Dim x As Long
With ws
For x = .Cells.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
If WorksheetFunction.CountA(.Rows(x)) = 0 Then
ws.Rows(x).Delete
End If
Next
End With
'(3) Insert 5 columns (WORKS)
Columns("A:F").Insert Shift:=xlToRight
'(4) Label columns (WORKS)
Range("$A$1").Value = "ServLabel"
Range("$B$1").Value = "Primary IP"
Range("$C$1").Value = "DC"
Range("$D$1").Value = "Service ID"
Range("$E$1").Value = "Sheet"
'(5) Find and Copy Range (WORKS)
Dim lastRow As Long
With ws
lastRow = .Cells(.Rows.Count, "J").End(xlUp).Row
End With
Dim rFound As Range
On Error Resume Next
Set rFound = Cells.Find(What:="SERV-", _
After:=Cells(Rows.Count, Columns.Count), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
On Error GoTo 0
If rFound Is Nothing Then
Else
rFound.Select
Selection.Resize(lastRow, numcolumns + 4).Select
Selection.Copy
Range("A2").Select
ws.Paste
End If
'(8) Enter active sheet name in Column E (WORKS)
If ws.Range("A2") = "" Then
Else
Dim lastRow2 As Long
With ws
lastRow2 = .Cells(.Rows.Count, "d").End(xlUp).Row
End With
Range("E2").Select
Selection.Resize(lastRow2 - 1).Select
Selection = ws.Name
End If
Next ws
End Sub
Unless you have some other reason it's probably easier to just scan the sheets and copy the data to the summary.
Option Explicit
Sub summary()
Const SUM_SHEET = "Summary" ' name of smmary sheet
Const PREFIX = "SERV-*"
Dim wb As Workbook, ws As Worksheet, wsSum As Worksheet
Dim iRow As Long, iSumRow As Long
Dim iStartrow As Long, iLastRow As Long, rng As Range, cell As Range
Set wb = ActiveWorkbook
Set wsSum = wb.Sheets(SUM_SHEET)
wsSum.Range("A1:E1") = Array("ServLabel", "Primary IP", "DC", "Service ID", "Sheet")
iSumRow = 1
For Each ws In wb.Sheets
If ws.Name <> SUM_SHEET Then
' find column SERV-
On Error Resume Next
Set rng = ws.Cells.Find(PREFIX)
On Error GoTo 0
' set scan start/end row
If rng Is Nothing Then
MsgBox "Can't find " & PREFIX & " on " & ws.Name, vbCritical
GoTo SkipSheet
Else
iLastRow = ws.Cells(Rows.Count, rng.Column).End(xlUp).Row
iStartrow = rng.Row + 1
End If
Debug.Print ws.Name, "Col=", rng.Column, "iStartRow=", iStartrow, "iLastRow=", iLastRow
' scan the sheet and write to summary
For iRow = iStartrow To iLastRow
Set cell = ws.Cells(iRow, rng.Column)
' skip blank line
If Len(cell) > 0 Then
iSumRow = iSumRow + 1
cell.Resize(1, 4).Copy wsSum.Cells(iSumRow, 1)
wsSum.Cells(iSumRow, 5) = ws.Name
End If
Next
End If
SkipSheet:
Next
MsgBox iSumRow - 1 & " rows copied to " & wsSum.Name, vbInformation
End Sub