-2

Initial

Hi all, how can I convert the initial Excel table to the final table via VBA (on a separate sheet)?

Final

VBasic2008
  • 44,888
  • 5
  • 17
  • 28

1 Answers1

-1

UnPivot with VBA

  • I created this monster (a work in progress) a while ago. It is kind of spaghetti code, but it should work in your case.
  • TESTgetPivot is what you run. Just change Sheet1 and Sheet2 to your worksheet names and adjust the first cells A1 and A2. You won't get the headers though.
  • This can also easily (in a few clicks) be done with PowerQuery.

The Code

Option Explicit

Enum RCV
    RowsColumnsValues = 1
    RowsValuesColumns
    ColumnsRowsValues
    ColumnsValuesRows
    ValuesRowsColumns
    ValuesColumnsRows
End Enum

Sub TESTgetPivot()
    Dim srcfirst As Range
    Set srcfirst = ThisWorkbook.Worksheets("Sheet1").Range("A1")
    Dim Data As Variant
    Data = getPivot(srcfirst, 2, 1, True, RowsColumnsValues)
    If Not IsEmpty(Data) Then
        With ThisWorkbook.Worksheets("Sheet2").Range("A2")
            '.Worksheet.Cells.ClearContents
            .Resize(UBound(Data, 1), UBound(Data, 2)) = Data
        End With
    Else
        Debug.Print "No Data."
    End If
End Sub

Function getPivot(FirstCell As Range, _
                  Optional ByVal RowLabels As Long = 1, _
                  Optional ByVal ColumnLabels As Long = 1, _
                  Optional ByVal ByColumnLabels As Boolean = False, _
                  Optional ByVal Order As RCV = RCV.RowsColumnsValues) _
         As Variant
    
    ' Initialize error handling.
    
    Const ProcName As String = "getPivot"
    On Error GoTo clearError
    
    ' Validate parameters
    
    If FirstCell Is Nothing Then
        GoTo NoCell
    End If
    If RowLabels < 0 Then
        GoTo RowLabelsNegative
    End If
    If ColumnLabels < 0 Then
        GoTo ColumnLabelsNegative
    End If
    Dim ColRowVal As Variant
    ColRowVal = Array("RCV", "RVC", "CRV", "CVR", "VRC", "VCR")
    Dim CRV As Variant
    CRV = Application.Match(Order, ColRowVal, 0)
    If IsError(CRV) Then
        ColRowVal = Array(1, 2, 3, 4, 5, 6)
        CRV = Application.Match(Order, ColRowVal, 0)
        If IsError(CRV) Then
            GoTo CRVWrongParameter
        End If
    End If
    
    ' Define Source Range.
    
    ' Define Current Region ('rng').
    Dim rng As Range
    Set rng = FirstCell.CurrentRegion
    ' Define End Range ('rng').
    Set rng = FirstCell _
      .Resize(rng.Rows.Count + rng.Row - FirstCell.Row, _
              rng.Columns.Count + rng.Column - FirstCell.Column)
    
    ' Validate parameters.
    
    ' Retrieve Source Rows Count ('srCount').
    Dim srCount As Long
    srCount = rng.Rows.Count
    ' Retrieve Source Columns Count ('scCount').
    Dim scCount As Long
    scCount = rng.Columns.Count
    ' Declare Target Array ('Target').
    Dim Target As Variant
    ' Validate Row Labels and Column Labels.
    If srCount = 1 And scCount = 1 Then
        If RowLabels + ColumnLabels = 0 Then
            ReDim Target(1 To 1, 1 To 1)
            Target(1, 1) = rng.Value
            GoTo writeResult
        Else
            GoTo OneCellOnly
        End If
    End If
    If scCount < RowLabels + 1 Then
        GoTo ColumnsDeficit
    End If
    If srCount < ColumnLabels + 1 Then
        GoTo RowsDeficit
    End If
    
    ' Write values from Source Range to Source Array ('Source').
    
    Dim Source As Variant
    Source = rng.Value
    
    ' Prepare to write values from Source Array to Target Array.
    
    ' Calculate Target Rows Count ('trCount').
    Dim trCount As Long
    trCount = (srCount - ColumnLabels) * (scCount - RowLabels)
    ' Calculate Target Columns Count ('tcCount').
    Dim tcCount As Long
    tcCount = RowLabels + ColumnLabels + 1
    
    ' Define Target Array ('Target').
    'Dim Target As Variant
    ReDim Target(1 To trCount, 1 To tcCount)
    
    ' Declare Counters.
    Dim i As Long ' Source Rows Counter
    Dim j As Long ' Source Columns Counter
    Dim k As Long ' Target Rows Counter
    Dim l As Long ' Target Columns Counter
     
    ' Write values from Source Array to Target Array.
    
    Select Case Order
        Case 1 ' "RCV"
            If Not ByColumnLabels Then
                For i = 1 + ColumnLabels To srCount
                    For j = 1 + RowLabels To scCount
                        k = k + 1
                        For l = 1 To RowLabels
                            Target(k, l) = Source(i, l) ' R
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - RowLabels, j) ' C
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                    Next j
                Next i
            Else
                For j = 1 + RowLabels To scCount
                    For i = 1 + ColumnLabels To srCount
                        k = k + 1
                        For l = 1 To RowLabels
                            Target(k, l) = Source(i, l) ' R
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - RowLabels, j) ' C
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                    Next i
                Next j
            End If
        Case 2 ' "RVC"
            If Not ByColumnLabels Then
                For i = 1 + ColumnLabels To srCount
                    For j = 1 + RowLabels To scCount
                        k = k + 1
                        For l = 1 To RowLabels
                            Target(k, l) = Source(i, l) ' R
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - RowLabels - 1, j) ' C
                        Next l
                    Next j
                Next i
            Else
                For j = 1 + RowLabels To scCount
                    For i = 1 + ColumnLabels To srCount
                        k = k + 1
                        For l = 1 To RowLabels
                            Target(k, l) = Source(i, l) ' R
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - RowLabels - 1, j) ' C
                        Next l
                    Next i
                Next j
            End If
        Case 3 ' "CRV"
            If Not ByColumnLabels Then
                For i = 1 + ColumnLabels To srCount
                    For j = 1 + RowLabels To scCount
                        k = k + 1
                        For l = 1 To ColumnLabels
                            Target(k, l) = Source(l, j) ' C
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - ColumnLabels) ' R
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                    Next j
                Next i
            Else
                For j = 1 + RowLabels To scCount
                    For i = 1 + ColumnLabels To srCount
                        k = k + 1
                        For l = 1 To ColumnLabels
                            Target(k, l) = Source(l, j) ' C
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - ColumnLabels) ' R
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                    Next i
                Next j
            End If
        Case 4 ' "CVR"
            If Not ByColumnLabels Then
                For i = 1 + ColumnLabels To srCount
                    For j = 1 + RowLabels To scCount
                        k = k + 1
                        For l = 1 To ColumnLabels
                            Target(k, l) = Source(l, j) ' C
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - ColumnLabels - 1) ' R
                        Next l
                    Next j
                Next i
            Else
                For j = 1 + RowLabels To scCount
                    For i = 1 + ColumnLabels To srCount
                        k = k + 1
                        For l = 1 To ColumnLabels
                            Target(k, l) = Source(l, j) ' C
                        Next l
                        For l = l To l
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - ColumnLabels - 1) ' R
                        Next l
                    Next i
                Next j
            End If
        Case 5 ' "VRC"
            If Not ByColumnLabels Then
                For i = 1 + ColumnLabels To srCount
                    For j = 1 + RowLabels To scCount
                        k = k + 1
                        For l = 1 To 1
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - 1) ' R
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - RowLabels - 1, j) ' C
                        Next l
                    Next j
                Next i
            Else
                For j = 1 + RowLabels To scCount
                    For i = 1 + ColumnLabels To srCount
                        k = k + 1
                        For l = 1 To 1
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - 1) ' R
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - RowLabels - 1, j) ' C
                        Next l
                    Next i
                Next j
            End If
        Case 6 ' "VCR"
            If Not ByColumnLabels Then
                For i = 1 + ColumnLabels To srCount
                    For j = 1 + RowLabels To scCount
                        k = k + 1
                        For l = 1 To 1
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - 1, j) ' C
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - ColumnLabels - 1) ' R
                        Next l
                    Next j
                Next i
            Else
                For j = 1 + RowLabels To scCount
                    For i = 1 + ColumnLabels To srCount
                        k = k + 1
                        For l = 1 To 1
                            Target(k, l) = Source(i, j) ' V
                        Next l
                        For l = l To l + ColumnLabels - 1
                            Target(k, l) = Source(l - 1, j) ' C
                        Next l
                        For l = l To l + RowLabels - 1
                            Target(k, l) = Source(i, l - ColumnLabels - 1) ' R
                        Next l
                    Next i
                Next j
            End If
        ' Not possible
    End Select
        
    ' Write result and exit.
writeResult:
    
    getPivot = Target
    GoTo ProcExit

' Labels

NoCell:
    Debug.Print "'" & ProcName & "': No First Cell Range ('Nothing')."
    GoTo ProcExit

RowLabelsNegative:
    Debug.Print "'" & ProcName & "': Headers Columns can only be 0 or positive."
    GoTo ProcExit

ColumnLabelsNegative:
    Debug.Print "'" & ProcName & "': Headers Rows can only be 0 or positive."
    GoTo ProcExit

CRVWrongParameter:
    Debug.Print "'" & ProcName & "': Order can contain either a combination " _
              & "of the letters ""R"", ""C"" and ""V"" or a number from 1 to 6."
    GoTo ProcExit

OneCellOnly:
    Debug.Print "'" & ProcName & "': There is one cell only."
    GoTo ProcExit

ColumnsDeficit:
    Debug.Print "'" & ProcName & "': Not enough columns."
    GoTo ProcExit

RowsDeficit:
    Debug.Print "'" & ProcName & "': Not enough rows."
    GoTo ProcExit

clearError:
    Debug.Print "'" & ProcName & "': " & vbLf _
              & "    " & "Run-time error '" & Err.Number & "':" & vbLf _
              & "        " & Err.Description
    On Error GoTo 0
    GoTo ProcExit

ProcExit:
    
End Function
  • The following image is showing what the code is covering. Your case is the first green one, except that your data has two row labels and one more column.

enter image description here

VBasic2008
  • 44,888
  • 5
  • 17
  • 28