using vba excel to unpivot with multiple categories (1 w/ 4 columns & 1 w/ 5 columns) of data

blackmamba89

New Member
Joined
Jun 28, 2022
Messages
8
Office Version
  1. 2019
Platform
  1. MacOS
Hello, I work with a lot of spreadsheets on my job and one of the most important ones comes from a survey and automatically imports into a spreadsheet in Excel. Unfortunately, the survey displays multiples of hours#1 instead of just putting it into one column and so and so forth as seen below in Tb#1. My goal is to convert the Tb#1 to look like Tb#2 using vba through unpivoting the columns so that it will be easier for my colleagues to work with the data. Of course, below is just some fake data but similar in format. I have also posted my code below. I'm getting an error: "Object variables w/ block variable not set 91" at the bolded line . Any help will be appreciated!

usrCompanyDept.#Dept1Dept2Dept3Dept4Hr1Hr1Hr1Hr1Hr2Hr2Hr2Hr3Hr3Hr4
xxxxOS1Train20
xxxxOPC2Poxy1Poxy24538
xxxxOxy R4H1H2H3H422893625
xxxxHPK3Test1Test2Test3995290
xxxxMano1Porp42
xxxxMacro2Otto1Otto27523

I want it to look like this.

usrCompanyDept.#DeptHrs
xxxxOS1Train20
xxxxOPC2Poxy145
xxxxOPC2Poxy238
xxxxOxy R4H122
xxxxOxy R4H289
xxxxOxy R4H336
xxxxOxy R4H425
xxxxHPK3Test199
xxxxHPK3Test252
xxxHPK3Test390
xxxxMano1Porp42
xxxxMacro2Otto175
xxxxMacro2Otto223

Rich (BB code):
Option Explicit

Sub TransformData()

Dim sh1 As Worksheet: Dim sh2 As Worksheet: Dim hdr
Dim rgDept As Range: Dim cell As Range:
Dim i As Long: Dim cnt As Long: Dim r As Long: Dim rgFill As Range: Dim rgHr As Range


Dim q As Integer
Worksheets("Sheet1").Select
q = 1
Do While Cells(q, 1) <> ""
   Cells(q, 8) = Cells(q, 8) & Cells(q, 9) & Cells(q, 10) & Cells(q, 11) & Cells(q,
12) & Cells(q, 13) & Cells(q, 14) _
    & Cells(q, 15) & Cells(q, 16) & Cells(q, 17)
    q = q + 1
Loop
Columns("H:H").EntireColumn.AutoFit
Sheet1.Range("H1").Value = "Hrs"

'setting the sheet into variable - change if needed
Set sh1 = Sheets("Sheet1"): Set sh2 = Sheets("Sheet2")
'clear all cells in sh2
sh2.Cells.ClearContents

'the header which will be in sh2 coming from sh1 header as hdr variable
hdr = Array("Usr", "Company", "Dept1", "Dept2", "Dept3", "Dept4", "Hr1", "Hr2",
"Hr3", "Hr4")

'put the data from sh1 to sh2 according to the header name defined in rgFill
For i = LBound(hdr) To UBound(hdr)
    sh1.Columns(sh1.Rows(1).Find(hdr(i)).Column).Copy Destination:=sh2.Columns(i + 1)
Next

'start row
r = 2

Do
'set the range for Unit Name according to the looped row into variable rgUnit _
this is how it will be pasted on Sheet 2
Set rgDept = sh2.Range(sh2.Cells(r, 3), sh2.Cells(r, 6)) ' sets the range of the Unit
Set rgHr = rgDept.Offset(0, 4)

'count how many data in rgUnit as cnt variable
cnt = Application.CountA(rgUnit)

    'if cnt > 1, copy the looped row then insert under it as many as cnt - 1
    If cnt > 1 Then
        sh2.Rows(r).Copy
        sh2.Rows(r + 1 & ":" & r + cnt - 1).Insert Shift:=xlDown
        Application.CutCopyMode = False
    End If

'fill the unit name
Set rgFill = rgDept.Resize(1, 1)
For Each cell In rgDept.SpecialCells(xlCellTypeConstants)
    rgFill.Value = cell.Value
    Set rgFill = rgFill.Offset(1, 0)
Next

'fill the number of actual hours
Set rgFill = rgHr.Resize(1, 1)
On Error Resume Next
For Each cell In rgHr.SpecialCells(xlCellTypeConstants)
On Error GoTo 0
    rgFill.Value = cell.Value
    Set rgFill = rgFill.Offset(1, 0)
Next

'increase the row value by add the cnt value
r = r + cnt
   
' Don't change this one.
Loop Until Application.CountA(sh2.Range(sh2.Cells(r, 3), sh2.Cells(r, 6))) = 0 
'finish the loop when rgUnit has no data

'delete unneeded column
rgDept.Resize(rgUnit.Rows.Count, 3).Offset(0, 1).EntireColumn.Delete

'give the correct name for unit and color header in sh2
sh2.Range("H1").Value = "Hrs"

Sheets(2).Buttons.Delete

MsgBox "Data converted!"

End Sub
 
Last edited by a moderator:
Nothing else :)
Sorry to bother you again. I promise this is the last time. I played around with the code you gave me. It works great up until I start to get up to 15 categories. It still works but some data is missing in a few rows (see picture). My total categories I have for my real spreadsheet is 19 categories. The spreadsheet is extremely long and is almost impossible to paste here using the table function and mini table upload, so I have attached a link to download it. Also here is my code. How do I fix this? The link below to my google drive contains the excel file I'm working with.

Google Drive: Sign-in

This image is the result. Notice that rows disappear once I get up to 15 categories
Screen Shot 2022-07-06 at 10.13.21 PM.png


Here is the code:
VBA Code:
Sub blackmamba()
   Dim Ary As Variant, Nary As Variant, Cary As Variant
   Dim r As Long, c As Long, nr As Long, cc As Long
   
   Cary = Array("0853", 6898, 113128, 143143)
   With Sheets("Sheet1")
      Ary = .Range("A2:DM" & .Range("A" & Rows.Count).End(xlUp).Row).Value2
   End With
   ReDim Nary(1 To UBound(Ary) * 4, 1 To 19)
   
   For r = 1 To UBound(Ary)
      For c = 4 To 7
         If Ary(r, c) = "" Then Exit For
         nr = nr + 1
         Nary(nr, 1) = Ary(r, 1): Nary(nr, 2) = Ary(r, 2): Nary(nr, 3) = Ary(r, 3)
         Nary(nr, 4) = Ary(r, c)
         For cc = Left(Cary(c - 4), 2) To Right(Cary(c - 4), 2) Step 15
            Nary(nr, 5) = Nary(nr, 5) & Ary(r, cc)
            Nary(nr, 6) = Nary(nr, 6) & Ary(r, cc + 1)
            Nary(nr, 7) = Nary(nr, 7) & Ary(r, cc + 2)
            Nary(nr, 8) = Nary(nr, 8) & Ary(r, cc + 3)
            Nary(nr, 9) = Nary(nr, 9) & Ary(r, cc + 4)
            Nary(nr, 10) = Nary(nr, 10) & Ary(r, cc + 5)
            Nary(nr, 11) = Nary(nr, 11) & Ary(r, cc + 6)
            Nary(nr, 12) = Nary(nr, 12) & Ary(r, cc + 7)
            Nary(nr, 13) = Nary(nr, 13) & Ary(r, cc + 8)
            Nary(nr, 14) = Nary(nr, 14) & Ary(r, cc + 9)
            Nary(nr, 15) = Nary(nr, 15) & Ary(r, cc + 10)
            Nary(nr, 16) = Nary(nr, 16) & Ary(r, cc + 11)
            Nary(nr, 17) = Nary(nr, 17) & Ary(r, cc + 12)
            Nary(nr, 18) = Nary(nr, 18) & Ary(r, cc + 13)
            Nary(nr, 19) = Nary(nr, 19) & Ary(r, cc + 14)
         Next cc
      Next c
   Next r
   With Sheets("Sheet2")
      .UsedRange.ClearContents
      .Range("A1").Resize(, 19).Value = Array("usr", "Company", "Dept.#", "Dept", "Hrs", "Tr", "F", "A", "HOH", "M", "R", "SO", "BIG", _
      "T", "P", "X", "Y", "Z", "Tin")
      .Range("A2").Resize(nr, 19).Value = Nary
   End With
End Sub
 
Upvote 0

Excel Facts

Test for Multiple Conditions in IF?
Use AND(test, test, test, test) or OR(test, test, test, ...) as the logical_test argument of IF.
Ok, the main problem is that you are now looking at columns in the hundreds, so you cannot use Left 2 & right 2.
Try it like
VBA Code:
Sub blackmamba()
   Dim Ary As Variant, Nary As Variant, Cary As Variant
   Dim r As Long, c As Long, nr As Long, cc As Long
   
   Cary = [{8,53;68,98;113,128;143,143}]
   With Sheets("Sheet1")
      Ary = .Range("A2:FA" & .Range("A" & Rows.Count).End(xlUp).Row).Value2
   End With
   ReDim Nary(1 To UBound(Ary) * 4, 1 To 19)
   
   For r = 1 To UBound(Ary)
      For c = 4 To 7
         If Ary(r, c) = "" Then Exit For
         nr = nr + 1
         Nary(nr, 1) = Ary(r, 1): Nary(nr, 2) = Ary(r, 2): Nary(nr, 3) = Ary(r, 3)
         Nary(nr, 4) = Ary(r, c)
         For cc = Cary(c - 3, 1) To Cary(c - 3, 2) Step 15
            Nary(nr, 5) = Nary(nr, 5) & Ary(r, cc)
            Nary(nr, 6) = Nary(nr, 6) & Ary(r, cc + 1)
            Nary(nr, 7) = Nary(nr, 7) & Ary(r, cc + 2)
            Nary(nr, 8) = Nary(nr, 8) & Ary(r, cc + 3)
            Nary(nr, 9) = Nary(nr, 9) & Ary(r, cc + 4)
            Nary(nr, 10) = Nary(nr, 10) & Ary(r, cc + 5)
            Nary(nr, 11) = Nary(nr, 11) & Ary(r, cc + 6)
            Nary(nr, 12) = Nary(nr, 12) & Ary(r, cc + 7)
            Nary(nr, 13) = Nary(nr, 13) & Ary(r, cc + 8)
            Nary(nr, 14) = Nary(nr, 14) & Ary(r, cc + 9)
            Nary(nr, 15) = Nary(nr, 15) & Ary(r, cc + 10)
            Nary(nr, 16) = Nary(nr, 16) & Ary(r, cc + 11)
            Nary(nr, 17) = Nary(nr, 17) & Ary(r, cc + 12)
            Nary(nr, 18) = Nary(nr, 18) & Ary(r, cc + 13)
            Nary(nr, 19) = Nary(nr, 19) & Ary(r, cc + 14)
         Next cc
      Next c
   Next r
   With Sheets("Sheet2")
      .UsedRange.ClearContents
      .Range("A1").Resize(, 19).Value = Array("usr", "Company", "Dept.#", "Dept", "Hrs", "Tr", "F", "A", "HOH", "M", "R", "SO", "BIG", _
      "T", "P", "X", "Y", "Z", "Tin")
      .Range("A2").Resize(nr, 19).Value = Nary
   End With
End Sub
 
Upvote 0
Solution
Ok, the main problem is that you are now looking at columns in the hundreds, so you cannot use Left 2 & right 2.
Try it like
VBA Code:
Sub blackmamba()
   Dim Ary As Variant, Nary As Variant, Cary As Variant
   Dim r As Long, c As Long, nr As Long, cc As Long
  
   Cary = [{8,53;68,98;113,128;143,143}]
   With Sheets("Sheet1")
      Ary = .Range("A2:FA" & .Range("A" & Rows.Count).End(xlUp).Row).Value2
   End With
   ReDim Nary(1 To UBound(Ary) * 4, 1 To 19)
  
   For r = 1 To UBound(Ary)
      For c = 4 To 7
         If Ary(r, c) = "" Then Exit For
         nr = nr + 1
         Nary(nr, 1) = Ary(r, 1): Nary(nr, 2) = Ary(r, 2): Nary(nr, 3) = Ary(r, 3)
         Nary(nr, 4) = Ary(r, c)
         For cc = Cary(c - 3, 1) To Cary(c - 3, 2) Step 15
            Nary(nr, 5) = Nary(nr, 5) & Ary(r, cc)
            Nary(nr, 6) = Nary(nr, 6) & Ary(r, cc + 1)
            Nary(nr, 7) = Nary(nr, 7) & Ary(r, cc + 2)
            Nary(nr, 8) = Nary(nr, 8) & Ary(r, cc + 3)
            Nary(nr, 9) = Nary(nr, 9) & Ary(r, cc + 4)
            Nary(nr, 10) = Nary(nr, 10) & Ary(r, cc + 5)
            Nary(nr, 11) = Nary(nr, 11) & Ary(r, cc + 6)
            Nary(nr, 12) = Nary(nr, 12) & Ary(r, cc + 7)
            Nary(nr, 13) = Nary(nr, 13) & Ary(r, cc + 8)
            Nary(nr, 14) = Nary(nr, 14) & Ary(r, cc + 9)
            Nary(nr, 15) = Nary(nr, 15) & Ary(r, cc + 10)
            Nary(nr, 16) = Nary(nr, 16) & Ary(r, cc + 11)
            Nary(nr, 17) = Nary(nr, 17) & Ary(r, cc + 12)
            Nary(nr, 18) = Nary(nr, 18) & Ary(r, cc + 13)
            Nary(nr, 19) = Nary(nr, 19) & Ary(r, cc + 14)
         Next cc
      Next c
   Next r
   With Sheets("Sheet2")
      .UsedRange.ClearContents
      .Range("A1").Resize(, 19).Value = Array("usr", "Company", "Dept.#", "Dept", "Hrs", "Tr", "F", "A", "HOH", "M", "R", "SO", "BIG", _
      "T", "P", "X", "Y", "Z", "Tin")
      .Range("A2").Resize(nr, 19).Value = Nary
   End With
End Sub
That did the trick! I can finally apply what I've learned from this to real data. Thank you very much for taking the time! If you ever teach a class on this stuff, I'll be the first to sign up lol. Thanks again!
 
Upvote 0

Forum statistics

Threads
1,224,823
Messages
6,181,175
Members
453,021
Latest member
Justyna P

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