VBA to Create a report

NYEXCEL1

Board Regular
Joined
Apr 17, 2013
Messages
123
Per the below grid, I am looking to have VBA take the data for each Silo pull the entire row (client, Silo, Jan, Feb, etc) onto a new worksheet also including the header row and total the months. So for example, the Group 1 worksheet would have 2 lines for client "a" and "d" under the header (ideally alphabetically by client) and sum each month Column.

Thanks in advance to the Excel community!


ClientSILOJanuaryFebruary
Client agroup 1 $ 1,000.00 $ 1,500.00
Client bgroup 2 $ 2,000.00 $ 5,000.00
Client cgroup 3 $ 3,000.00 $ 2,500.00
Client dgroup 1 $ 4,000.00 $ 6,800.00
Client egroup 2 $ 5,100.00 $ 3,500.00

<colgroup><col><col><col span="2"></colgroup><tbody>
</tbody>
 

Excel Facts

How to find 2nd largest value in a column?
MAX finds the largest value. =LARGE(A:A,2) will find the second largest. =SMALL(A:A,3) will find the third smallest
Hi there,

Are you saying you want one column of values in each created sheet, which sums all month columns? Or are you saying you want all rows of data to be copied to each newly created sheet and include all month columns?

Also, how many columns do you have? Does it change? If so, how can you tell where to get the data? What should each newly created sheet be called? Whatever is the SILO value? And if it already exists, should it be cleared of data and re-populated?
 
Upvote 0
Here are the answers to your questions.

You can have the VBA create one workbook with a worksheet for each silo (ie. group 1, group 2, etc). Each worksheet should contain show the header row (Client, Silo, January, February,........december, Total) with all the data underneath in alpha order by client.

The data set has (Client, Silo, January, February,........december,) the only changes to the data is when a new months income is added. Sheets can be titled with the silo name. sheets should be cleared and repopulated each import.
 
Upvote 0
Thanks. I'm not sure I follow. If the sheets can be cleared of data and repopulated AND you want a workbook created when this is run, how does that work? It would seem to be one or the other. To be clear, I'm saying there are two scenarios here:

  1. Create a new workbook every time, populate it with sheets named how you describe. This would negate any need to clear the sheets, because they would always be new.
  2. Use the same workbook the data sheet is housed in. This would mean we would have to check for the sheets existence, clear it if found, and populate it with data.

Which one of those sounds more correct?
 
Upvote 0
I think you could use something like the below code. Note the 'Option' settings at the top. Those are module-level settings. You must declare those at the top of the module, above all other code, and you can only declare them once per module. If you're adding this code into an existing module, make sure you follow those rules.

Code:
Option Explicit
Option Base 1


Sub BreakOutSiloData()
    
    Dim NewBook As Workbook
    Dim Book As Workbook
    Dim SourceSheet As Worksheet
    Dim Sheet As Worksheet
    Dim Silos As Collection
    Dim GroupIndex As Long
    Dim SiloCount As Long
    Dim SilosCreated As Long
    Dim SiloIndex As Long
    Dim ValueColumns As Long
    Dim ValueRows As Long
    Dim SiloKey As String
    Dim Silo As Variant
    Dim SourceData As Variant
    Dim Headers As Variant
    Dim Values As Variant
    
    ' Set these two objects as desired.
    Set Book = ThisWorkbook
    Set SourceSheet = Book.Worksheets("Sheet1")
    Set NewBook = Workbooks.Add(xlWBATWorksheet)
    
    On Error Resume Next
    With SourceSheet
        Headers = .Range("A1", .Cells(1, .Columns.Count).End(xlToLeft))
        SourceData = .Range("A2", .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, UBound(Headers, 2))).Value
    End With
    On Error GoTo 0
    
    On Error GoTo ErrorExit
    
    Application.DisplayAlerts = False
    Application.EnableEvents = False
    Application.ScreenUpdating = False
    
    If IsEmpty(Headers) Or IsEmpty(SourceData) Then
        MsgBox "We couldn't find the data.", vbExclamation + vbOKOnly
        Exit Sub
    End If
    
    Set Silos = New Collection
    
    For SiloIndex = LBound(SourceData, 1) To UBound(SourceData, 1)
        
        SiloKey = CStr(SourceData(SiloIndex, 2))
        
        If Not InCollection(Silos, SiloKey) Then
            
            If Not IsEmpty(Values) Then Erase Values
            Values = Application.Index(Application.Transpose(SourceData), , SiloIndex)
            Silos.Add Values, SiloKey
            
        Else
            
            If Not IsEmpty(Values) Then Erase Values
            Values = Silos.Item(SiloKey)
            SiloCount = UBound(Values, 2) + 1
            ValueRows = UBound(Values, 1)
            ValueColumns = UBound(Values, 2) + 1
            ReDim Preserve Values(1 To ValueRows, 1 To ValueColumns)
            
            For GroupIndex = 1 To UBound(SourceData, 2)
                Values(GroupIndex, ValueColumns) = SourceData(SiloIndex, GroupIndex)
            Next GroupIndex
            
            Silos.Remove SiloKey
            Silos.Add Values, SiloKey
            
        End If
        
        
    Next SiloIndex
    
    SilosCreated = 0
    For Each Silo In Silos
        
        On Error GoTo SkipSilo
        
        SiloKey = Silo(2, 1)
        NewBook.Worksheets.Add After:=NewBook.Worksheets(NewBook.Worksheets.Count)
        Set Sheet = NewBook.Worksheets(NewBook.Worksheets.Count)
        Sheet.Name = SiloKey
        
        Sheet.Range("A1").Resize(1, UBound(Headers, 2)).Value = Headers
        Sheet.Range("A2").Resize(UBound(Silo, 2), UBound(Silo, 1)).Value = Application.Transpose(Silo)
        
        Sheet.Range("A2").Resize(UBound(Silo, 2), UBound(Silo, 1)).Sort Key1:=Sheet.Range("A2"), Order1:=xlAscending, Header:=xlNo
        
        SilosCreated = SilosCreated + 1
        
SkipSilo:
        
    Next Silo
    
    NewBook.Worksheets(1).Delete
    MsgBox "Data transfer complete. (" & SilosCreated & " of " & Silos.Count & ")", vbInformation + vbOKOnly
    
ResumeExit:
    
    Application.DisplayAlerts = True
    Application.EnableEvents = True
    Application.ScreenUpdating = True
    
    Exit Sub
    
ErrorExit:
    
    MsgBox "Something went wrong with the data transfer.", vbCritical + vbOKOnly
    GoTo ResumeExit
    
End Sub


Public Function InCollection(ByVal CheckCollection As Collection, ByVal CheckKey As String) As Boolean
'
' Returns True if the specified key is found in the specified collection.
'
' Parameters:   CheckCollection. Collection. Required. The collection to search in.
'               CheckKey. String. Required. The string key to search in collection for.
'
    On Error Resume Next
    InCollection = CBool(Not IsEmpty(CheckCollection(CheckKey)))
    On Error GoTo 0

End Function
 
Upvote 0
this is great. I cant imagine how extensive the Macro is, thought it would be a lot shorter. Thank you for the efforts! Can you add language to total the columns as well and also have the Months show as as the full name and not the date format (ie. MMMM)

thanks
 
Upvote 0
This is short. ;)

For the total column, from your earlier reply, it sounded like you may already have one. Can this be the case? If so, do you want to replace it? Will there always be a January column, but a dynamic number of columns after that, potentially up to 11 more, ending in December? If you can provide the logic, we can provide the code.
 
Last edited:
Upvote 0
When I mentioned, "column total" i meant a total for each month on each silo worksheet. so there would be a total for each month as well as a row total (which is after December). Also the Months show up as in a date format, would like to read January, February, etc.

Let me know if that makes sense.


On a side note, what is the best way to learn, VBA. while i tried a few online courses. I learn best by doing examples. any thoughts on how you got to this level?

thanks
 
Upvote 0
Hmm, for the headers maybe just format, after this line
Code:
        Sheet.Range("A1").Resize(1, UBound(Headers, 2)).Value = Headers
..add this line
Code:
        Sheet.Range("A1").Resize(1, UBound(Headers, 2)).NumberFormat = "mmmm"
It won't affect text, but all numbers will be forced to a date format. We could dynamically find this if it becomes an issue, but since we know that's the only data in the headers, it should be fine.

For the total column, if I understand you correctly, you should be able to add some code. Put it after this line..
Code:
        Sheet.Range("A2").Resize(UBound(Silo, 2), UBound(Silo, 1)).Sort Key1:=Sheet.Range("A2"), Order1:=xlAscending, Header:=xlNo
... add something like this..
Code:
        LastColumnLetter = Split(Sheet.Range("A2").Offset(0, UBound(Silo, 1) - 1).Address, "$")(1)
        Sheet.Range("A2").Offset(0, UBound(Silo, 1)).Resize(UBound(Silo, 2), 1).Formula = "=SUM(C2:" & LastColumnLetter & "2)"
        Sheet.Range("A1").Offset(0, UBound(Silo, 1)).Value = "Total"

You'll have to declare 'LastColumnLetter' as a String with the other variables at the top of the routine. This assumes the values will always start in column C and end in the last column with data.

Learning VBA can be a fickle thing. It largely depends on the person learning. For me, I learned right here on this forum. I say I was self-taught, as in I had no formal training, never attended a program or took a course, or anything like that. What it really means is I learned from others here. I would say it takes the insatiably curious to learn the best. I was always taking others examples and solutions, and applying it on my own, figuring things out. It's slower that way, but organic, and can be beneficial as the learning is built upon your own successes and failures.

There are a few courses out there on VBA. I've seen Jon Acampora's VBA Pro Course and it's pretty good. I've seen this Udemy course before, but I've only seen the sample videos. While I wouldn't describe it as "ultimate", they look decent. I'm working with some good people to create some VBA courses now as well. And of course there's always books here in the bookstore, like the VBA and Macros Excel 2016.

In the end persistence will pay off. Reading a lot helps. Knowing that what you see, read, and hear, is only one way of doing things, and there are many. Most code you see posted online will be, in some form, inefficient. Doesn't mean it won't work, but good, efficient code can be hard to find. Hope this helps answer your questions.
 
Upvote 0

Forum statistics

Threads
1,215,327
Messages
6,124,294
Members
449,149
Latest member
mwdbActuary

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top