0

I'm trying to split a table into different sheets, relevant to column 1 of my sheet

Main sheet

So say i have a sheet called 109 i want all 109's entries (entire rows of the table copied over)

109 sheet

With Columns and Rows in Red

enter image description here

 Sub populate()

Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

Dim lngLastRow As Long

Sheets("Data").Select
Range("D11").Select

' Set NE sheets

Set jc109 = Sheets("109")
Set jj112 = Sheets("112")
Set gd126 = Sheets("126")
Set pw216 = Sheets("216")
Set sa223 = Sheets("223")
Set ms269 = Sheets("269")
Set ad363 = Sheets("363")


lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row


With Range("D11", "P" & lngLastRow)

.AutoFilter

' Copy NE stock info

.AutoFilter Field:=1, Criteria1:="109"
.Copy jc109.Range("D11")
.AutoFilter Field:=1, Criteria1:="112"
.Copy jj112.Range("D11")
.AutoFilter Field:=1, Criteria1:="126"
.Copy gd126.Range("D11")
.AutoFilter Field:=1, Criteria1:="216"
.Copy pw216.Range("D11")
.AutoFilter Field:=1, Criteria1:="223"
.Copy sa223.Range("D11")
.AutoFilter Field:=1, Criteria1:="269"
.Copy ms269.Range("D11")
.AutoFilter Field:=1, Criteria1:="363"
.Copy ad363.Range("D11")

.AutoFilter

End With

Call emailsheets

  Application.ScreenUpdating = True
 .EnableEvents = True
 Application.Calculation = xlCalculationAutomatic

End Sub

If if have a row of .... as entry's then it works but copies over a row of ... at the top, not too much of an issue i pasted it to a hidden row. but then it seem sto throw #REF errors in the cells if i don't have an entry for each engineer number it is searching for.

  • Confirming you're splitting by column 2 (is this column B?) Engineer number? And you want all rows where Eng no. = "109" copied to sheet 109, starting in cell B2? What is this cell "D11" you use everywhere? – Carol Dec 11 '17 at 21:45
  • Also, does this help: https://stackoverflow.com/questions/16039774/excel-vba-copying-and-pasting-visible-table-rows-only – Carol Dec 11 '17 at 21:48
  • @Carol, I'm assuming the `D11` to be the starting point, or at least the 11th row to contain the first record. But I might be wrong. – SilentRevolution Dec 11 '17 at 21:54
  • Sorry D11 is the 1st engineer no in the series i.e the 1st row. Yes i am splitting by colum2 (which happens to be D). – Not Very good at VBA YET Dec 11 '17 at 21:54
  • I've realised the #REF error is due to my main table using this formula to get the data from column A =OFFSET($A$1,(ROW(2:2)*7)*1,0) – Not Very good at VBA YET Dec 11 '17 at 21:56
  • So column `D` is the column with the header `Eng No.` and row 11 is that `Entry 0` or `Entry 1`? For future reference, it may be easier to include the Excel row and column headers in your picture. – SilentRevolution Dec 11 '17 at 22:03

1 Answers1

1

I've taken the liberty of writing a different sub for the following reasons.

  1. As your data set expands, so does the number of times your code has to access the sheet, which could mean a significant reduction in performance. I've used arrays to eliminate this problem all data is read in one go and then processed and then written.
  2. In your code you've (inadvertently) used ActiveWorkbook. Usually this doesn't create a problem but may cause issues if you have multiple workbooks open. Active refers to whatever is active, regardless of where your code is. You should have a look at this

Some assumptions that apply

  • Sheets for all engineers are already present, if not this will throw an error
  • The row "Entry 0" has been removed, my code does not require this row, it can however be adapted to incorporate it if it is required by your document.
  • With the "Entry 0" row gone I've assumed the value "112" in column "Eng No." to be in cell D11 and the value "0" in column "Entry" to be in cell C11
  • Only values are copied over, the actual values are not.

Here is the code

Option Explicit

Sub populate()

    Dim arrData() As Variant, arrEngData() As Variant
    Dim arrEngNo() As Long
    Dim wsData As Worksheet, wsEng As Worksheet
    Dim i As Long, j As Long, k As Long

    With Application
        .ScreenUpdating = False
        .EnableEvents = False
        .Calculation = xlCalculationManual
    End With

    Set wsData = ThisWorkbook.Worksheets("Data")

    'Get all Engineer numbers
    With wsData
        arrData = .Range(.Cells(11, 4), .Cells(11, 4).End(xlDown))                      'I've altered the way the array is collected, instead of looking for the first value in column D from the bottom up, it now looks for the last value in column D going down column D starting at row 11
    End With

    'Get unique engineer numbers
    ReDim arrEngNo(0)                                                                   'I've tweaked the start of the procedure so it does not automatically record the first value it encounters, in case this is a 0
    For i = LBound(arrData, 1) To UBound(arrData, 1)
        If UBound(arrEngNo) = 0 And Not arrData(i, 1) = 0 Then                          'I've added a check to so that no 0 value is entered as an engineer's number
            ReDim arrEngNo(1 To 1)                                                      'If a valid engineer's number is found, resize the array
            arrEngNo(1) = arrData(1, 1)
        Else
            For j = LBound(arrEngNo) To UBound(arrEngNo)
                If arrEngNo(j) = arrData(i, 1) Or arrData(i, 1) = 0 Then                'I've added a check to also skip 0 values besides already recorded engineer's numbers
                    Exit For
                ElseIf j = UBound(arrEngNo) And Not arrEngNo(j) = arrData(i, 1) Then
                    ReDim Preserve arrEngNo(1 To UBound(arrEngNo) + 1)
                    arrEngNo(UBound(arrEngNo)) = arrData(i, 1)
                End If
            Next j
        End If
    Next i

    'Collect all records in array to process
    With wsData
        arrData = .Range(.Cells(11, 4), .Cells(11, 4).End(xlDown).Offset(0, 12))        'I've altered the way the array is collected, instead of looking for the first value encountered from the bottom up in column P, which could be empty and so potentially it could miss records, it now looks down to the last value encounterd in column D (which is the last formula in column D) and then moves over to column P
    End With

    'Iterate through all available engineer numbers
    For i = LBound(arrEngNo) To UBound(arrEngNo)

        'Reset the array for the engineer specific records
        ReDim arrEngData(1 To 13, 0)

        'Iterate through the records and copy the relevant records to engineer specific array
        For j = LBound(arrData, 1) To UBound(arrData, 1)
            'If engineer numbers match, then copy data to engineer specific array
            If arrData(j, 1) = arrEngNo(i) Then
                If UBound(arrEngData, 2) = 0 Then
                    ReDim arrEngData(1 To 13, 1 To 1)
                Else
                    ReDim Preserve arrEngData(1 To 13, 1 To UBound(arrEngData, 2) + 1)
                End If

                'Copy record
                For k = 1 To 13
                    arrEngData(k, UBound(arrEngData, 2)) = arrData(j, k)
                Next k
            End If
        Next j

        'Set the engineer worksheet
        Set wsEng = ThisWorkbook.Worksheets(CStr(arrEngNo(i)))

        'Write collected records to engineer worksheet
        With wsEng
            .Range(.Cells(11, 4), .Cells(11, 4).Offset(UBound(arrEngData, 2) - 1, UBound(arrEngData, 1) - 1)) = Application.Transpose(arrEngData)
        End With
    Next i

    wsData.Activate

    Call emailsheets

    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = xlCalculationAutomatic
    End With

End Sub

Performance:

  • 10,000 records, 500 unique engineer numbers processed in 1,33837890625 seconds
  • 1,000,000 records, 1,000 unique engineer numbers processed in 116,3740234375 seconds

I hope this works for you and creates a starting point from which you can expand your VBA knowledge.

SilentRevolution
  • 1,495
  • 1
  • 16
  • 31
  • Thanks for the effort its much appreciated.That throws up an error on the 'Set the engineer worksheet Set wsEng = ThisWorkbook.Worksheets(CStr(arrEngNo(i))) I've double checked and all engineer numbers have relevent sheets. i.e Eng 109 has Sheet (109). – Not Very good at VBA YET Dec 11 '17 at 23:44
  • Does it give the "Subscript out of range" error? If so this means it's trying to refer to a sheet which does not exist. If you place your cursor on that line and press `F9` it should place a red dot on the left side and make the line a deep red color. If you now run this code by pressing `F5` it should pause there. if you then type `?arrengno(i)` in the immediate window (`CTRL + G` to show the immediate window) and press `ENTER` it should show you what `arrEngNo(i)` actually is at that point. If it shows something other than the name of an existing sheet, it will throw an error. – SilentRevolution Dec 11 '17 at 23:52
  • I'ts probably got something to do with a wrong assumption regarding the starting cell of the data on my end. – SilentRevolution Dec 11 '17 at 23:59
  • It initially comes up with a Runtime error '9', after selecting Debug, and following what you have typed above, I get a compile error: Sub or function not defined. D11 is the 1st entry of data, i've added a new picture above with row and column identifiers. – Not Very good at VBA YET Dec 12 '17 at 07:57
  • Im not sure if i made it clear but the engineer sheets are basically copies of the main sheet, so they need the data put into D11 as well, not sure if this would have made any difference. – Not Very good at VBA YET Dec 12 '17 at 08:20
  • I don't understand why it would throw this error. Would it be at all possible for you to share the actual document with me so I can have a look at that? Possibly a copy with data removed. – SilentRevolution Dec 12 '17 at 09:19
  • Shared it here https://drive.google.com/open?id=0ByX9emQjSzKudlFjN3NMTnZNU0staFNaMDkzZGU2MkpwUUZr Is that ok? – Not Very good at VBA YET Dec 12 '17 at 16:07
  • That's perfect I see what happens now, In column D, you've used formulae which to the naked eye look like empty cells but to VBA this is however not the case it's value is `0` rather than `Empty` which are very different values to VBA. I've made the alteration and shared the document with you directly on google drive. and I've edited my answer to reflect the alterations. – SilentRevolution Dec 12 '17 at 22:48
  • Also, on your sheet `Data` you were missing row `29` I've added it in the document I shared with you. – SilentRevolution Dec 13 '17 at 00:14
  • SilentRevolution that is fantastic. Thank you so much for your help. Its much appreciated. What you've done if way over my head. Time to get some books and do some reading / practise I think. Thanks again it works a treat. – Not Very good at VBA YET Dec 13 '17 at 07:59
  • Glad I could help, @NotVerygoodatVBAYET, I've learned through StackOverflow, Google and just trying. If you've found my answer helpful, please consider accepting it as the answer to your question by clicking the check mark at the top left of the answer. – SilentRevolution Dec 13 '17 at 10:33
  • Hi if your still viewing this thread SilentRevolution, There is a slight issue where the date when copied over changes from UK to USA. It actually swaps the month and date characters around? any ideas? – Not Very good at VBA YET Feb 20 '18 at 12:57