Home » excel » vba – Pushing Data from Datasheet Into Generated Template Worksheets

vba – Pushing Data from Datasheet Into Generated Template Worksheets

Posted by: admin May 14, 2020 Leave a comment


I am extending my macro building efforts to organize and shift data retrieved from a mainframe. The data is in string form, similar to that discussed here. I am also making use of the macros developed with SO advice and aid from these questions(1)(2).

I have spent many hours developing this particular portion of the macro, to the point of working on other parts concurrently due to the difficulties I have encountered in development – perhaps due to inexperience.

To put it succinctly, I am generating worksheets, renaming them and pushing data into those worksheets, which are generated and then filled with a blank form. I am attempting to do it on the basis of rows, as each row is essentially a record that I am pushing to a worksheet form. There are 20-some fields I am utilizing and pushing over to each new worksheet.

I originally attempted a highly nested loop, and then considered how I might make use of structures. However, as I grew more confused, I switched to a discrete model, as I noted I still had not figured out how to make proper use of the Cells (cell address property) of the Range Object.

The code is as follows:

'This subroutine is intended to take filtered data and use it to fill forms.
'These forms use a very basic text template worksheet, which is copied over for each worksheet.
'In general, these forms will number from 1 to 100, for discussion purposes.
'The idea is that each row of data in the DataSheet will be used to fill each worksheet tab.

Sub DataShifter()

Dim RngOne As Range, RngCell As Range
Dim RngTwo As Range
Dim RngThree As Range, RngCell2 As Range 'RngCell2 is not currently in use
Dim RngRow As Range

Dim LastCell As Long

Dim arrList() As String, LongCount As Long

'Define range data within the Crtieria Sheet
With Sheets("Criteria")
    LastCell = .Range("A" & Sheets("Criteria").Rows.Count).End(xlUp).row
    Set RngOne = .Range("A2:A" & LastCell)
End With

'Push values into the array
LongCount = 0
For Each RngCell In RngOne
    ReDim Preserve arrList(LongCount)
    arrList(LongCount) = RngCell.Text
    LongCount = LongCount + 1

'Filter the values to the desired criteria stored in the array.
With Sheets("Sheet1")

'For when this process is repeated.
If .FilterMode Then .ShowAllData

.Range("A:A").AutoFilter Field:=1, Criteria1:=arrList, Operator:=xlFilterValues

End With

'Add a Sheet to contain the filtered criteria
Sheets.Add After:=Sheets(1)
Sheets(2).Name = "DataSheet"

'With the original dataset, snag all existing data based on the range in Sheet Criteria.
'This avoids potential empty junk data and potential blanks pulled from the mainframe.
With Sheets("Sheet1")

LastCell = .Range("A" & Sheets("Criteria").Rows.Count).End(xlUp).row
Set RngTwo = .Range("A2:AA" & LastCell)

End With

'Push data into DataSheet worksheet, so data is sequential

'Define the ranges used within the sheet
With Sheets("DataSheet")
LastCell = .Range("A" & Sheets("Criteria").Rows.Count).End(xlUp).row
Set RngThree = .Range("A2:A" & LastCell)

End With

'For each row in the range, (1) generate a new datasheet, and copy the form from the template to the new sheet.
'(2) Rename the datasheet to be the value in Row 1, Column 1 ("A1").
'(3) Copy over information to the form based on column location in the Datasheet.
'This method, even if made functional, is both procedural and limited in scope. Recursion with text matching will be the end goal for this form.
For Each RngRow In RngThree.Rows

Sheets.Add After:=Sheets(1)

'Grab the text form from the Template and push it into the new sheet.

Sheets(2).Name = Sheets("DataSheet").Cells(RngRow, 1).Value

Sheets(2).Range("B3") = Sheets("DataSheet").Cells(RngRow, 1).Value
Sheets(2).Range("D3") = Sheets("DataSheet").Cells(RngRow, 2).Value
Sheets(2).Range("F3") = Sheets("DataSheet").Cells(RngRow, 3).Value
Sheets(2).Range("B5") = Sheets("DataSheet").Cells(RngRow, 4).Value
Sheets(2).Range("B10") = Sheets("DataSheet").Cells(RngRow, 5).Value
Sheets(2).Range("B7") = Sheets("DataSheet").Cells(RngRow, 6).Value
Sheets(2).Range("D10") = Sheets("DataSheet").Cells(RngRow, 7).Value
Sheets(2).Range("F10") = Sheets("DataSheet").Cells(RngRow, 8).Value
Sheets(2).Range("B13") = Sheets("DataSheet").Cells(RngRow, 9).Value
Sheets(2).Range("D13") = Sheets("DataSheet").Cells(RngRow, 10).Value
Sheets(2).Range("F13") = Sheets("DataSheet").Cells(RngRow, 11).Value
Sheets(2).Range("B16") = Sheets("DataSheet").Cells(RngRow, 12).Value
Sheets(2).Range("D16") = Sheets("DataSheet").Cells(RngRow, 13).Value
Sheets(2).Range("F16") = Sheets("DataSheet").Cells(RngRow, 14).Value
Sheets(2).Range("B19") = Sheets("DataSheet").Cells(RngRow, 15).Value
Sheets(2).Range("D19") = Sheets("DataSheet").Cells(RngRow, 16).Value
Sheets(2).Range("F19") = Sheets("DataSheet").Cells(RngRow, 17).Value
Sheets(2).Range("B21") = Sheets("DataSheet").Cells(RngRow, 18).Value
Sheets(2).Range("D21") = Sheets("DataSheet").Cells(RngRow, 19).Value
Sheets(2).Range("B23") = Sheets("DataSheet").Cells(RngRow, 20).Value
Sheets(2).Range("D23") = Sheets("DataSheet").Cells(RngRow, 21).Value

 'Concatenate values from certain fields into one field
Sheets(2).Range("B26") = Sheets("DataSheet").Cells(RngRow, 23).Value & Cells(RngRow, 24).Value & Cells(RngRow, 24).Value & Cells(RngRow, 25).Value & Cells(RngRow, 26).Value & Cells(RngRow, 27).Value

Next RngRow

End Sub

Currently, executing this code results in a type mismatch, first on line 84: Sheets(2).Name = Sheets("DataSheet").Cells(RngRow, 1).Value, and then on the proceeding lines if line 84 is commented out. I am uncertain how I should correct this to make my code function effectively, and I am asking for a fix to this particular issue.

Of more general concern is my approach, and I would please also welcome any suggestions, advice, approaches or improvements to consider for this macro – although the fix is of paramont importance before I make any optimization efforts whatsoever.

How to&Answers:

In the lines causing errors instead of RngRow Use RngRow.Row.

RngRow is a Range. RngRow.Row will return the number for the first row of the RngRow.

Cells expects a RowIndex(a number) and a ColumnIndex. When you provide a Range (Instead of a number) and a ColumnIndex it throws the type match error you’ve indicated.

Here is one example of how you could shorten/improve your code instead of:

Sheets.Add After:=Sheets(1)  
'Grab the text form from the Template and push it into the new sheet. 

You should be able to use this with the same results though I would try to avoid select as much as possible:

'Copy the Template into a new sheet.
Sheets("TemplateSheet2").Copy After:=Sheets(1)