Tested in Excel 365 (16.8730.2046) 64-bit. All links open in new tab.
This is useful when you have a cross-tab and you need the data from which it was derived.
Of course, you can easily unpivot using PowerPivot, see here how.
- Public Sub ConvertTableToData()
- Dim LastRow, xLastCol, LastCol
- Dim currRow, currRowValue
- Dim i, j, DataSheet, FinalSheet
- Dim HeaderArray(), CountArray()
- DataSheet = ActiveSheet.Name
- FinalSheet = "Data"
- ' delete existing output sheet, if any
- Application.DisplayAlerts = False
- If SheetExists(FinalSheet) Then Sheets(FinalSheet).Delete
- Application.DisplayAlerts = True
- 'creates new sheet with header
- Sheets.Add After:=Sheets(Sheets.Count)
- ActiveSheet.Name = FinalSheet
- Cells(1, 1).Value = "Rows"
- Cells(1, 2).Value = "Cols"
- Cells(1, 3).Value = "Value"
- ' get the pasting position
- Sheets(DataSheet).Activate
- LastRow = Range("A" & Rows.Count).End(xlUp).Row
- LastCol = Cells(1, Columns.Count).End(xlToLeft).Column
- xLastCol = LastCol - 1
- HeaderArray = Range(Cells(1, 2), Cells(1, LastCol))
- currRow = 2
- For i = 2 To LastRow
- CountArray = Range(Cells(i, 2), Cells(i, LastCol))
- currRowValue = Cells(i, 1).Value
- With Sheets(FinalSheet)
- 'paste-transpose the header and the data
- .Range(.Cells(currRow, 2), .Cells(currRow + xLastCol - 1, 2)).Value = Application.Transpose(HeaderArray)
- .Range(.Cells(currRow, 3), .Cells(currRow + xLastCol - 1, 3)).Value = Application.Transpose(CountArray)
- 'fill in the rows with the row label
- For j = currRow To currRow + xLastCol - 1
- .Cells(j, 1).Value = currRowValue
- Next j
- End With
- currRow = currRow + xLastCol
- Next i
- MsgBox "Done!"
- End Sub
SheetExists function is here
You can use this file to test the code.