Home > OS >  How to Transpose header row value group by particular column value
How to Transpose header row value group by particular column value

Time:02-06

I have some data in excel in following format:

Cust_Name    Prod1     Prod2    Prod3     Prod4    Prod5
A            0         100      120       0        0
B            145       120      168       0        200
C            350       300      0        340       0

I need to convert the following format in below-mentioned report format.

I want to transpose those product in a column group by Cust_Name which has value >0 else it shouldn't be part of final output report.

I have tried many pivot option but it didn't work.

Required Output:

Cust_Name      Product       Price
A              Prod2         100
               Prod3         120
Total A        -             220
B              Prod1         145
               Prod2         120
               Prod3         168
               Prod5         200
Total B        -             633
C              Prod1         350
               Prod2         300
               Prod4         340
Total C        -             890

CodePudding user response:

You can do this with PowerQuery.

Select any cell in your source data. Use Data>Get & Transform Data>From Table/Range.

The PowerQuery editor will open, like this:

enter image description here

Select the Cust_Name column by clicking the column header. Use Transform>Unpivot Columns>Unpivot Other Columns:

enter image description here

At this point, optionally filter the Value column to exclude 0.

Now use Home>Close & Load to put the data back into your workbook.

You can now create a pivot table to get your sub totals:

enter image description here

Here is the query from the Advanced Editor dialog in the PowerQuery editor:

let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Cust_Name", type text}, {"Prod1", Int64.Type}, {"Prod2", Int64.Type}, {"Prod3", Int64.Type}, {"Prod4", Int64.Type}, {"Prod5", Int64.Type}}),
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Cust_Name"}, "Attribute", "Value")
in
    #"Unpivoted Other Columns"

CodePudding user response:

If you need a VBA solution, please test the next code. It will return in another sheet the processing result. It is designed to process as many products are on the sheet (in the headers row). The code should be very fast, all processing being done in memory:

Sub TransposeSummarize()
  Dim sh As Worksheet, shRet As Worksheet, lastR As Long, lastCol As Long, dict As Object
  Dim arr, arrFin, arrDict, i As Long, J As Long, k As Long, count As Long
  
  Set sh = ActiveSheet
  Set shRet = sh.Next 'use here the sheet you need returning
  lastR = sh.Range("A" & sh.rows.count).End(xlUp).row          'last row
  lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column 'last column
  arr = sh.Range("A1", sh.cells(lastR, lastCol)).Value 'place the range in an array for faster iteration
  ReDim arrDict(UBound(arr, 2) - 2)                    'Redim the arrDict for first time
  Set dict = CreateObject("Scripting.Dictionary")      'set the Dictionary (Scripting) object
  For i = 2 To UBound(arr)                             'iterate between the array elements (rows and columns)
        For J = 2 To UBound(arr, 2)
            arrDict(J - 2) = arr(i, J)                 'fill arrDict with values on the i row
        Next J
        dict(arr(i, 1)) = arrDict                      'place the array as dictionary item
        Erase arrDict: ReDim arrDict(UBound(arr, 2) - 2) 'reinitialize the necessary array
  Next i

  ReDim arrFin(1 To dict.count * lastCol   1, 1 To 3): k = 1
  'Put the Headers in the final array:
  arrFin(1, 1) = "Cust_Name": arrFin(1, 2) = "Product": arrFin(1, 3) = "Price": k = 2
  
  For i = 0 To dict.count - 1             'process the dictionary keys/items and create the final array
        arrFin(k, 1) = dict.Keys()(i)
        For J = 0 To UBound(dict.Items()(i))
            If dict.Items()(i)(J) <> 0 Then
                arrFin(k, 2) = arr(1, J   2): arrFin(k, 3) = dict.Items()(i)(J)
                count = count   dict.Items()(i)(J): k = k   1
            End If
        Next J
        arrFin(k, 1) = "Total " & dict.Keys()(i): arrFin(k, 2) = "-": arrFin(k, 3) = count
        count = 0: k = k   1
  Next i
  'drop the array content at once, at the end of the code:
  shRet.Range("A1").resize(k - 1, UBound(arrFin, 2)).Value = arrFin
End Sub
  •  Tags:  
  • Related