BabyPeach
BabyPeach

Reputation: 21

Loop issue VBA - paste on last row

I am fairly new to VBA and struggling to understand why my macro is not working.

The context: I have an Excel workbook with 3 sheets:

What I am trying to do I want to :

Desired output I would have the bloc with all the accounts with one department next to it, and as many blocs as there are departments on the list. On the sheet it would look like this: extract excel

My code so far

Sub Macro1()
'
' Macro1 Macro
'
Dim lrow As Long
Dim i As Integer

lrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row


For i = 1 To 47

Sheets("Accounts").Select
Range("A2:A178").Select
Selection.Copy

Sheets("Account and Dpt").Select
Range("A" & lrow + 1).Select
ActiveSheet.Paste

Sheets("Departments").Select '
Range("B" & i + 1).Select
Application.CutCopyMode = False
Selection.Copy

Sheets("Account and Dpt").Select
Range("B" & lrow + 1).Select
Range(Selection, Selection.End(xlUp)).Select
ActiveSheet.Paste

i = i + 1

Next i

End Sub

When I run it - nothing happens; can you help me understanding how to fix it ?

Many thanks!!

Upvotes: 2

Views: 1318

Answers (3)

VBasic2008
VBasic2008

Reputation: 54883

Double Loop Through Columns

Option Explicit

Sub PopulateAnD()

    ' Accounts
    Const aName As String = "Accounts"
    Const aFirst As String = "A2"
    ' Departments
    Const dName As String = "Departments"
    Const dFirst As String = "B2"
    ' Accounts and Departments
    Const adName As String = "Account and Dpt"
    Const adFirst As String = "A2"
    Const adClearBelow As Boolean = True
    
    ' Workbook
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    
    ' Accounts
    Dim aws As Worksheet: Set aws = wb.Worksheets(aName)
    Dim afCell As Range: Set afCell = aws.Range(aFirst)
    Dim arg As Range: Set arg = RefColumn(afCell)
    If arg Is Nothing Then Exit Sub
    Dim arCount As Long: arCount = arg.Rows.Count
    Dim aData As Variant: aData = GetRange(arg)
    
    ' Departments
    Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
    Dim dfCell As Range: Set dfCell = dws.Range(dFirst)
    Dim drg As Range: Set drg = RefColumn(dfCell)
    If drg Is Nothing Then Exit Sub
    Dim drCount As Long: drCount = drg.Rows.Count
    Dim dData As Variant: dData = GetRange(drg)
    
    ' Accounts and Departments
    
    ' Define the array.
    Dim adrCount As Long: adrCount = arCount * drCount
    Dim adData As Variant: ReDim adData(1 To adrCount, 1 To 2)
    
    ' Write to the array.
    Dim ar As Long
    Dim dr As Long
    Dim adr As Long
    For dr = 1 To drCount
        For ar = 1 To arCount
            adr = adr + 1
            adData(adr, 1) = aData(ar, 1)
            adData(adr, 2) = dData(dr, 1)
        Next ar
    Next dr
    
    ' Write to the range.
    Dim adws As Worksheet: Set adws = wb.Worksheets(adName)
    Dim adfCell As Range: Set adfCell = adws.Range(adFirst)
    WriteData adfCell, adData, adClearBelow

    'wb.Save

End Sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose:      Creates a reference to the one-column range from the first cell
'               of a range ('FirstCell') through the bottom-most non-empty cell
'               of the first cell's worksheet column.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefColumn( _
    ByVal FirstCell As Range) _
As Range
    If FirstCell Is Nothing Then Exit Function
    
    With FirstCell.Cells(1)
        Dim lCell As Range
        Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
            .Find("*", , xlFormulas, , , xlPrevious)
        If lCell Is Nothing Then Exit Function
        Set RefColumn = .Resize(lCell.Row - .Row + 1)
    End With

End Function

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose:      Returns the values of a range in a 2D one-based array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetRange( _
    ByVal rg As Range) _
As Variant
    If rg Is Nothing Then Exit Function
    
    If rg.Rows.Count + rg.Columns.Count = 2 Then ' only one cell
        Dim Data As Variant: ReDim Data(1 To 1, 1 To 1): Data(1, 1) = rg.Value
        GetRange = Data
    Else ' multiple cells
        GetRange = rg.Value
    End If

End Function

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose:      Writes the values from a 2D array ('Data') to a range
'               defined by its first cell ('FirstCell') and by the size
'               of the array. Optionally (by default), clears the cells
'               below the resulting range.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub WriteData( _
        ByVal FirstCell As Range, _
        ByVal Data As Variant, _
        Optional ByVal doClearBelow As Boolean = True)
    If FirstCell Is Nothing Then Exit Sub
        
    On Error GoTo ClearError ' if not a 2D array
    
    Dim rCount As Long: rCount = UBound(Data, 1) - LBound(Data, 1) + 1
    Dim cCount As Long: cCount = UBound(Data, 2) - LBound(Data, 2) + 1
    
    With FirstCell.Cells(1)
        Dim wsrCount As Long: wsrCount = .Worksheet.Rows.Count
        Dim wscCount As Long: wscCount = .Worksheet.Columns.Count
        If rCount > wsrCount - .Row + 1 Then Exit Sub
        If cCount > wscCount - .Column + 1 Then Exit Sub
        .Resize(rCount, cCount).Value = Data
        If doClearBelow Then
            .Resize(wsrCount - .Row - rCount + 1, cCount).Offset(rCount).Clear
        End If
    End With

ProcExit:
    Exit Sub
ClearError:
    Resume ProcExit
End Sub

Upvotes: 0

Shri
Shri

Reputation: 164

Please always AVOID .Select and .Activate statements. I am sure you will learn this quickly as you go forward in VBA.

I have modified the solution given above by CDP1802, though it would work fine. But in case if you have variable number of rows in the sheet "Account" next time the data will not be copied till the end. Hence this modification -

add lrowD and lrowA to find last row in Department and Accounts respectively

Sub Macro2()

Dim lrow As Long, i As Integer
Dim lrowD as long, lrowA as long

Application.ScreenUpdating = False


'lrowD = Sheets("Departments").Cells(Rows.Count, 1).End(xlUp).Row 'Not using it currently
lrowA = Sheets("Accounts").Cells(Rows.Count, 1).End(xlUp).Row


For i = 1 To 47
    lrow = Sheets("Account and Dpt").Cells(Rows.Count, 1).End(xlUp).Row

    Sheets("Accounts").Range("A2:A" & lrowA).Copy _
        Sheets("Account and Dpt").Range("A" & lrow + 1)
    
    Sheets("Departments").Range("B" & i + 1).Copy _
        Sheets("Account and Dpt").Range("B" & lrow + 1).Resize((lrowA-1))
    
Next i
Application.ScreenUpdating = True

End Sub

Upvotes: 0

CDP1802
CDP1802

Reputation: 16322

Update lrow after pasting the accounts

Option Explicit

Sub Macro1()
    '
    ' Macro1 Macro
    '
    Dim lrow As Long, i As Integer
    lrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
    
    For i = 1 To 47
    
        Sheets("Accounts").Select
        Range("A2:A178").Select
        Selection.Copy
        
        Sheets("Account and Dpt").Select
        Range("A" & lrow + 1).Select
        ActiveSheet.Paste
        
        Sheets("Departments").Select '
        Range("B" & i + 1).Select
        Application.CutCopyMode = False
        Selection.Copy
            
        Sheets("Account and Dpt").Select
        lrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
    
        Range("B" & lrow).Select
        Range(Selection, Selection.End(xlUp).Offset(1)).Select
        ActiveSheet.Paste
    
    Next i
End Sub

Or more simply

Sub Macro2()
 
    Dim lrow As Long, i As Integer
    
    Application.ScreenUpdating = False
    For i = 1 To 47
        lrow = Sheets("Account and Dpt").Cells(Rows.Count, 1).End(xlUp).Row
    
        Sheets("Accounts").Range("A2:A178").Copy _
            Sheets("Account and Dpt").Range("A" & lrow + 1)
        
        Sheets("Departments").Range("B" & i + 1).Copy _
            Sheets("Account and Dpt").Range("B" & lrow + 1).Resize(177)
        
    Next i
    Application.ScreenUpdating = True

End Sub

Upvotes: 1

Related Questions