Reputation: 53
Need some help with a VBA script for excel to convert data in a column into a new Row if certain column not empty. Duplicate the initial data in a couple of primary columns into a new row and copy/condense the data from another column into that new row if the cell in the column is not empty. My file has 1,000's of records and I don't have the time to individually separate them. Best if seen visually below (sorry not enough rep to post image)
Starts like this.
Col1.......Col2.....Col3.....Col4
ItemA.....$2.........................
ItemB.....$2........$4.............
ItemC.....$6.........................
ItemD.....$2........$3.........$5
ItemE.....$9.........................
Finish like this
Col1.......Col2
ItemA.....$2
ItemB.....$2
ItemB.....$4
ItemC.....$6
ItemD.....$2
ItemD.....$3
ItemD.....$5
ItemE.....$9
This is how I would handle in vb and html with recordset loops. Just need advice on excel where recordset or range is determined and how it starts through columns.
Dim Col1, Col2, Col3, Col4, RowData, CondenseData, FinalData
FinalData = ""
While ((RS.Items__numRows <> 0) AND (NOT RS.Items.EOF)) 'recordset loop how in Excel?
CondenseData = ""
Col1 = RS.Col1Data 'how to go from column to column in row in excel?
Col2 = RS.Col2Data
Col3 = RS.Col3Data
Col4 = RS.Col4Data
If Not IsNull(Col2) Then
CondenseData = Col1 & ", " & Col2
RowData = CondenseData & "<br />" ' create a new row with the revised data if not empty?
End If
If Not IsNull(Col3) Then
CondenseData = Col1 & ", " & Col3
RowData = CondenseData & "<br />"
End If
If Not IsNull(Col4) Then
CondenseData = Col1 & ", " & Col4
RowData = CondenseData & "<br />"
End If
FinalData = FinalData & RowData
RS.Items__index=RS.Items__index+1
RS.Items__numRows=RS.Items__numRows-1
RS.Items.MoveNext()
Wend
Upvotes: 1
Views: 272
Reputation: 14764
The following will work, and is extremely fast.
Public Sub Condense(rIn As Range, rOut As Range)
Dim v As Variant, vOut As Variant
Dim i As Long, j As Long, c As Long
v = rIn.Value2
ReDim vOut(1 To UBound(v, 1) * UBound(v, 2), 1 To 2)
For i = 1 To UBound(v, 1)
For j = 2 To UBound(v, 2)
If Len(v(i, j)) Then
c = c + 1
vOut(c, 1) = v(i, 1)
vOut(c, 2) = v(i, j)
End If
Next
Next
rOut.Resize(c, 2) = vOut
End Sub
Upvotes: 0
Reputation: 1134
I took your example data and created this code. I tested it and it works. I pass in a parameter with the number of rows rather than obtain that from the source sheet. You can tweak that if need be to make it fully dynamic.
Sub FormatSheet(aRowCount As Integer)
Dim iSheet2Row As Integer
iSheet2Row = 1
For i = 1 To aRowCount
Dim bHasData As Boolean
bHasData = True
Dim iCol As Integer
iCol = 1
Do While bHasData
Dim varColHeader As String
If Len(Trim(Cells(i, iCol).Value)) > 0 Then
If iCol = 1 Then
'get col header value
varColHeader = Cells(i, 1)
Else
'write col header
Worksheets("Sheet2").Cells(iSheet2Row, 1).Value = varColHeader
'write col data
Worksheets("Sheet2").Cells(iSheet2Row, 2).Value = Worksheets("Sheet1").Cells(i, iCol).Value
iSheet2Row = iSheet2Row + 1
End If
Else
bHasData = False
End If
iCol = iCol + 1
Loop
Next i
End Sub
Upvotes: 0
Reputation: 50064
In VBA we use Ranges instead of Recordsets. They are somewhat kind of-ish the same-ish kind of... But anyway.. you can kind of think of it as a recordset if that helps. It's just there is really no relationship across records/rows and fields/columns like there would be in a recordset.
Anyhow, an example of how to go about this
Sub example()
Dim rngToConvert as Range
Dim rngRow as Range
Dim rngCell as Range
'write this out to a new tab so we need incrementer to keep track of rows
Dim writeRow as integer
writeRow = 1
'The entire range we are converting
Set rngToConvert = Sheets("yoursheetname").Range("A1:Z1000")
'Loop through each row
For each rngRow in rngToConvert.Rows
'Loop through each cell (field)
For each rngCell in rngRow.Cells
'ignore that first row since that has your "ItemA", "ItemB", etc..
'Also ignore if it doesn't have a value
If rngCell.Column > 1 And rngCell.Value <> "" Then
'Write that row header
Sheets("SheetYouAreWritingOutTo").Cells(writeRow, 1).value = rngRow.Cells(1,1)
'Write this non-null value
Sheets("SheetYouAreWritingOutTo").Cells(writeRow, 2).value = rngCell.Value
'Increment Counter
writeRow = writeRow + 1
End if
Next rngCell
Next rngRow
End sub
There's probably a faster way to go about it that doesn't require excel to iterate through every single cell in the range, but this is fast and dirty and will do the job. Apologies if I messed up the syntax anywhere. I wrote it on the fly in notepad.
Upvotes: 1