Workbook split hangs up here - vba

The project: It deals with very sensitive HR/performance data, and I need to send 1000s of employees' data to their individual managers (about 100 managers who can only see their team's data, and no one else's), so I need about 100 files split (1 for each manager).
The file: - Many different tabs, separated by role. - First column is a unique identifier made by concatenating the Manager's name with the job title ex. John Stevens_Office Manager
The task: John Stevens will have team members in many different job roles, and needs all that data in one file, separated into tabs by job role.
Based on that sample data, the ideal macro would give me 3 files with 3 worksheets in each, and 1 row of data in each worksheet. However, I will settle for the worksheet being split into multiple files.
Here is my code.
Sub SplitWB()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
ActiveWorkbook.Save
Dim OutputFolderName As String
OutputFolderName = ""
Set myDlg = Application.FileDialog(msoFileDialogFolderPicker)
myDlg.AllowMultiSelect = False
myDlg.Title = "Select Output Folder for Touchstone Files:"
If myDlg.Show = -1 Then OutputFolderName = myDlg.SelectedItems(1) & "\" Else Exit Sub
Set myDlg = Nothing
Application.CutCopyMode = False
'''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''
Dim d As Object, c As Range, k, tmp As String, unique(500)
i = 0
With ActiveSheet
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set d = CreateObject("scripting.dictionary")
For Each c In Range(Cells(1, 1), Cells(lastRow, 1))
tmp = Trim(c.Value)
If Len(tmp) > 0 Then d(tmp) = d(tmp) + 1
Next c
For Each k In d.keys
Debug.Print k, d(k)
i = i + 1
unique(i) = k
Next k
UniqueCount = i
'start deleting
For i = 1 To UniqueCount
'Actions for new workbook
wpath = Application.ActiveWorkbook.FullName
wbook = ActiveWorkbook.Name
wsheet = ActiveSheet.Name
ActiveWorkbook.SaveAs Filename:=OutputFolderName & unique(i), FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
For j = 1 To lastRow
If Range("A" & j) <> "" And Range("A" & j) <> unique(i) Then
Rows(j).Delete
j = j - 1
End If
Next
'hide helper columns
' If HideC = False And DeleteC = True Then
Columns("A:D").Hidden = True
' End If
'
Range("E8").Select
'Select Instructions tab
'Worksheets("Guidelines").Activate
'Save new workbook
ActiveWorkbook.Close SaveChanges:=True
Workbooks.Open (wpath)
'ActiveWorkbook.Close False
Workbooks(wbook).Activate
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox ("Macro has completed successfully!" & vbNewLine & vbNewLine & "Generated files can be found in the following directory:" & vbNewLine & OutputFolderName)
End Sub
The code hangs at "If Range("A" & j) <> "" And Range("A" & j) <> unique(i) Then"
It is located about half-way into the code and the chunk starts with "For j = 1 To lastRow"
Please help. It will literally save me a day's work or more. Thanks!!!

Try
For j = lastRow to 1 step -1
If Range("A" & j) <> "" And Range("A" & j) <> unique(i) Then
Rows(j).Delete
End If
Next
instead. This allows you to loop backwards so when you delete a row it won't lose track of where you want j to be in the loop.

Related

Looping through cells in another workbook to copy specific values

I've been fighting with this for a couple days now, and am at a loss on what else to try. My goal is to have a prompt for where a workbook is saved, this spreadsheet is obtained from an external source and name/location can vary. After opening the workbook, switch over to the second sheet and start searching for the values to copy to the workbook the macro is run out of.
The code I have works great if I set a breakpoint at the calculation for the last row, and at the For loop. Without those 2 breakpoints, it appears that none of the information in the workbook loads before running the rest of the code.
Public Sub Clm2Count()
Dim i, j, k, last As Long
Dim wkbSource, wkbCrnt As Workbook
Dim str As Variant
Dim strArray()
strArray() = Array("THIS", "IS", "MY", "ARRAY")
Set wkbCrnt = ThisWorkbook
k = 1
With Application.FileDialog(msoFileDialogOpen)
.Filters.Clear
.Filters.Add "Excel 2007-13", "*.xlsx; *.xlsm; *.xlsa"
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
Application.ScreenUpdating = False
Set wkbSource = Workbooks.Open(.SelectedItems(1))
Application.ScreenUpdating = True
End If
End With
Sheets(2).Activate
Cells(5,1).Select 'Trying to activate a cell before calculating last, didn't work
last = wkbSource.Sheets(2).Cells(wkbSource.Sheets(2).Cells.Rows.Count, 1).End(xlUp).Row
For i = 51 To last
If InStr(1, wkbSource.Sheets(2).Cells(i, 2).Value, "TEST") > 0 Then
For Each str In strArray
If InStr(1, wkbSource.Sheets(2).Cells(i, 2).Text, str, vbTextCompare) > 0 Then
If InStr(1, wkbSource.Sheets(2).Cells(i, 2).Text, "A", vbTextCompare) > 0 Or InStr(1, Cells(i, 2).Text, "B", vbTextCompare) > 0 Then
If str = "MY" Then 'Specific value from the array
wkbSource.Sheets(2).Cells(i, 3).Copy
wkbCrnt.Sheets(1).Cells(k, 1).PasteSpecial
wkbCrnt.Sheets(1).Cells(k, 2).Value = "QC"
wkbCrnt.Sheets(1).Cells(k, 3).Value = i & ", " & str
k = k + 1
Exit For
End If
ElseIf InStr(1, wkbSource.Sheets(2).Cells(i, 2).Text, "C", vbTextCompare) > 0 Then
wkbSource.Sheets(2).Cells(i, 3).Copy
wkbCrnt.Sheets(1).Cells(k, 1).PasteSpecial
wkbCrnt.Sheets(1).Cells(k, 2).Value = "QC"
wkbCrnt.Sheets(1).Cells(k, 3).Value = i & ", " & str
k = k + 1
Exit For
Else
Exit For
End If
End If
Next str
wkbSource.Activate
End If
Next i
End Sub
Any ideas on what I might be overlooking?
Edit:
Here are images of the beginning and end of column A, with the identifiers removed
Beginning
End
Instead of Sheets(2).Activate use wkbSource.Sheets(2).Activate. Same goes for cells and any other kind of ranges you are using.
It is especially crucial to be as explicit as possible which is the target workbook when you have a multiple workbook interaction.
To find last row use this line:
last = wkbSource.Sheets(2).Cells(wkbSource.Sheets(2).Cells.Rows.Count, 1).End(xlUp).Row
Edit: The issue was caused by a hidden sheet - it is better to use sheets name in this case.

Counting Contiguous Sets of Data provided no other sets occur within 500 rows

I want to write some VBA code that will count how many sets of "contiguous rows of Ts" there are in a single column in a worksheet. However I want such data sets to only be counted if there are more than 500 rows after the final T in a set that contain F values. For example, if T values are found at rows 500-510, then rows 511- 1010 would have to contain F values for one to be added to the count. If another T is encountered before reaching 1010, then the code would "reset" the 500 row counter and begin again.
row 1 - 1000 = F
row 1001 - 1011 = T
row 1012 - 1600 = F
row 1601 - 1611 = T
row 1612 - 3000 = F
In this case the counter would display 2
Conversely:
row 1 - 1000 = F
row 1001 - 1011 = T
row 1012 - 1400 = F
row 1401 - 1411 = T
row 1412 - 3000 = F
The counter would only display 1 as the Ts in cluster 1001-1011 are <500 rows within cluster 1401-1411.
I am also aware that in some scenarios there may be a set of Ts that are within 500 rows of the end of overall data. These would also need to be ignored from the count (I.e. using the example above, if Ts occurred a 2,700 - 2710, in a set of data with 3,000 rows, these would need to be ignored from the count). Similarly I would need to exclude rows 1-500 from the count also.
I don't know if this would be possible or even how to begin writing the code for this, so any assistance will be greatly appreciated. Excerpt of data:
F
F
F
F
F
F
F
F
F
T
T
T
T
T
F
F
F
F
F
F
F
F
This is going to be added to a much larger macro which then goes to filter out all rows containing Ts and deleting them. However I want to perform the count of contiguous Ts first before taking this step.
Code for rest of macro (This code is called by another macro which takes the values generated and pastes them into a master file):
Sub RollMap_Ensocoat(Wb As Workbook)
Dim ws As Worksheet
Dim Rng As Range, Cell As Range
Dim finalRow As Long
'Set name of first sheet in spreadsheet to "1"
With Wb.Sheets(1)
.Name = "1"
End With
'Code to delete all rows that contain a "T" in column G" (Indicating a tab was fired and thus is waste)
With Sheets("1")
finalRow = .Range("G" & Rows.Count).End(xlUp).Row
.AutoFilterMode = False
With .Range("G4:G" & finalRow)
.AutoFilter Field:=1, Criteria1:="T"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
'Code to calculate all the important values of each reel that will be pasted into the master report.
End With
Set ws = Wb.Sheets.Add(After:=Sheets(Wb.Sheets.Count))
With ws
.Range("A3").FormulaR1C1 = "=MAX('1'!C)"
.Range("B3").Formula = "=A3*I3"
.Range("C3").Formula = "=SUBTOTAL(109,'1'!B4:B10000)"
.Range("D3").Formula = "=SUBTOTAL(109,'1'!C4:C10000)"
.Range("E3").Formula = "=SUBTOTAL(109,'1'!D4:D10000)"
.Range("F3").Formula = "=SUBTOTAL(109,'1'!E4:E10000)"
.Range("G3").Formula = "=SUBTOTAL(109,'1'!F4:F10000)"
.Range("H3").Formula = "=SUM(C3:G3)"
.Range("I3").Formula = "='1'!A1"
.Range("J3").Formula = "=H3/(A3*I3)"
.Range("K3").Value = "0.21"
.Range("L3").Value = Wb.Name
.Range("M3").Formula = "=Left(L3, Len(L3) - 4)"
.Range("M3").Copy
.Range("M3").PasteSpecial xlPasteValues
.Range("N3").Formula = "=RIGHT(M3, 11)"
.Range("O3").Formula = "=LEFT(N3,2) & ""/"" & MID(N3,3,2) & ""/20"" & MID(N3,5,2)"
.Range("P3").Formula = "=MID(N3,8,2)& "":"" & MID(N3,10,2)"
.Range("Q3").Formula = "=Left(L3, Len(L3) - 16)"
.Range("A3:Q3").Copy
.Range("A3:Q3").PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("A3:Q3").Copy
End With
End Sub
Code with Tim's suggested additions:
Sub Populate_Ensocoat()
On Error GoTo eh
Dim MyBook As String
Dim Wb As Workbook
Dim strFolder As String
Dim strFil As String
Dim StartTime As Double
Dim SecondsElapsed As Double
Dim xCount As Long
Dim SourceRang1 As Range
Dim FillRange1 As Range
'Code to improve performance
Application.ScreenUpdating = False
Application.EnableEvents = False
'Code to Prompt user to select file location
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
strFolder = .SelectedItems(1)
Err.Clear
End With
'Code to count how many files are in folder and ask user if they wish to continue based on value counted
strFil = Dir(strFolder & "\*.csv*")
Do While strFil <> ""
xCount = xCount + 1
strFil = Dir()
Loop
If MsgBox("You have selected " & xCount & " files. Are you sure you wish to continue?", vbYesNo) = vbNo Then GoTo eh
'Code to Start timer
StartTime = Timer
'Code to make final report sheet visible and launch sheet hidden
Sheet1.Visible = True
Sheet1.Activate
Sheets("Sheet3").Visible = False
'declaring existing open workbook's name
MyBook = ActiveWorkbook.Name
'Code to cycle through all files in folder and paste values into master report
strFil = Dir(strFolder & "\*.csv*")
Do While strFil <> vbNullString
Set Wb = Workbooks.Open(strFolder & "\" & strFil)
Call RollMap_Ensocoat(Wb)
Workbooks(MyBook).Activate
ActiveSheet.Paste
Selection.HorizontalAlignment = xlCenter
ActiveCell.Offset(1).Select
Wb.Close SaveChanges:=False
strFil = Dir
Loop
'Formatting of values in final report
Range("B:I").NumberFormat = "#,##0"
Range("J:K").NumberFormat = "0.000"
Range("L:L").NumberFormat = "0.00"
Range("P:P").NumberFormat = "dd/MM/yyyy"
Range("Q:Q").NumberFormat = "hh:mm"
'Code to add header data to report (i.e. total files, name of person who created report, date and time report was created)
Range("Y2").Value = Now
Range("H2").Value = "# of Files Reported on: " & xCount
Range("P2").Value = Application.UserName
'Re-enabling features disabled for improved macro performance that are now needed to display finished report
Application.EnableEvents = True
Application.ScreenUpdating = True
'Code to refresh sheet so that graphs display properly
ThisWorkbook.RefreshAll
'Code to automatically save report in folder where files are located. Overrides warning prompting user that file is being saved in Non-macro enabled workbook.
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:=strFolder & "\" & "Summary Report", FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
'Code to display message box letting user know the number of files reported on and the time taken.
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "Operation successfully performed on " & xCount & " files in " & SecondsElapsed & " seconds." & vbNewLine & vbNewLine & "Report created at location: " & Application.ActiveWorkbook.FullName, vbInformation
Done:
Exit Sub
eh:
MsgBox "No Folder Selected. Please select re-select a board grade"
End Sub
Sub RollMap_Ensocoat(Wb As Workbook)
Dim ws As Worksheet
Dim finalRow As Long
'Set name of first sheet in spreadsheet to "1"
With Wb.Sheets(1)
.Name = "1"
.Range("H1").Formula = "=TCount(G3:G10000)"
End With
'Code to delete all rows that contain a "T" in column G" (Indicating a tab was fired and thus is waste)
With Sheets("1")
finalRow = .Range("G" & Rows.Count).End(xlUp).Row
.AutoFilterMode = False
With .Range("G4:G" & finalRow)
.AutoFilter Field:=1, Criteria1:="T"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
'Code to calculate all the important values of each reel that will be pasted into the master report.
End With
Set ws = Wb.Sheets.Add(After:=Sheets(Wb.Sheets.Count))
With ws
.Range("A3").FormulaR1C1 = "=MAX('1'!C)"
.Range("B3").Formula = "=A3*I3"
.Range("C3").Formula = "=SUBTOTAL(109,'1'!B4:B10000)"
.Range("D3").Formula = "=SUBTOTAL(109,'1'!C4:C10000)"
.Range("E3").Formula = "=SUBTOTAL(109,'1'!D4:D10000)"
.Range("F3").Formula = "=SUBTOTAL(109,'1'!E4:E10000)"
.Range("G3").Formula = "=SUBTOTAL(109,'1'!F4:F10000)"
.Range("H3").Formula = "=SUM(C3:G3)"
.Range("I3").Formula = "='1'!A1"
.Range("J3").Formula = "=H3/(A3*I3)"
.Range("K3").Value = "0.21"
.Range("L3").Value = Wb.Name
.Range("M3").Formula = "=Left(L3, Len(L3) - 4)"
.Range("M3").Copy
.Range("M3").PasteSpecial xlPasteValues
.Range("N3").Formula = "=RIGHT(M3, 11)"
.Range("O3").Formula = "=LEFT(N3,2) & ""/"" & MID(N3,3,2) & ""/20"" & MID(N3,5,2)"
.Range("P3").Formula = "=MID(N3,8,2)& "":"" & MID(N3,10,2)"
.Range("Q3").Formula = "=Left(L3, Len(L3) - 16)"
.Range("R3").Formula = "='1'!H1"
.Range("A3:R3").Copy
.Range("A3:R3").PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("A3:R3").Copy
End With
End Sub
Function TCount(rng As Range)
Const GAP_SIZE As Long = 5 '<< low number for testing...
Dim rv As Long, i As Long, fCount As Long, n As Long, d
Dim haveT As Boolean
rv = 0
d = rng.Value
n = UBound(d, 1)
fCount = 0
If n > GAP_SIZE Then
For i = 1 To n
If d(i, 1) = "T" Then
fCount = 0
haveT = True
Else
fCount = fCount + 1
If fCount = GAP_SIZE And haveT Then
rv = rv + 1
haveT = False
End If
End If
Next i
End If
TCount = rv
End Function
Something like this.
You may need to adjust if I made wrong assumptions about your rules.
Function TCount(rng As Range)
Const GAP_SIZE As Long = 5 '<< low number for testing...
Dim rv As Long, i As Long, fCount As Long, n As Long, d
Dim haveT As Boolean, earlyT as Boolean
rv = 0
d = rng.Value
n = UBound(d, 1)
fCount = 0
If n > GAP_SIZE Then
For i = 1 To n
If d(i, 1) = "T" Then
fCount = 0
If i <= GAP_SIZE Then earlyT = True '<<EDIT
haveT = True
Else
fCount = fCount + 1
If fCount = GAP_SIZE And haveT Then
rv = rv + 1
haveT = False
End If
End If
Next i
End If
TCount = rv - IIf(earlyT, 1, 0) '<< EDIT
End Function

VBA loop to pull cell addresses and sum them in a cell in another master spreadsheetl

I have the following code but it doesn't get to me to quite where I want:
Public Sub populateFile()
Dim wbk As Workbook
Dim fileName As String
Dim path As String
Dim pulledFormula As String
Dim pulledPath As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
path = "C:\Users\Bob\Desktop\Source Files\"
fileName = Dir(path & "*.xlsx*")
Do While fileName <> ""
Set wbk = Workbooks.Open(path & fileName, UpdateLinks:=False)
j = 24
For i = 8 To 16
With Workbooks("MasterFile.xlsm").Sheets("Sheet1")
If Application.WorksheetFunction.CountA(Workbooks(fileName).Sheets("SummaryTab").Range(Cells(i - 1, j - 21), Cells(i - 1, j - 13))) > 0 Then
.Cells(i, j - 10).Value = fileName & vbNewLine & .Cells(i, j - 10).Value
For j = 15 To 23
pulledFormula = "+" & Application.WorksheetFunction.Index(Workbooks(fileName).Sheets("SummaryTab").Range("C6:K164"), _
Application.WorksheetFunction.Match(.Cells(i, 1), Workbooks(fileName).Sheets("SummaryTab").Range("A6:A164"), 0), _
Application.WorksheetFunction.Match(.Cells(6, j), Workbooks(fileName).Sheets("SummaryTab").Range("C5:K5"), 0)).Address(External:=True)
.Cells(i, j).Value = pulledFormula & .Cells(i, j).Formula
Next j
End If
End With
Next i
wbk.Close
fileName = Dir
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
End Sub
So I am trying to pull relevant (based on the index/match) cell addresses from a bunch of files in a directory. The next step is to iteratively add the addresses together with the + sign in the hope that in the end the master spreadsheet can have the sum of all the relevant cells from all the opened files in one cell (and to do this for a bunch of cells as well). The exact problem is that Excel refuses to evaluate the resulting concatenated formula. Would really appreciate any ideas on how to improve this code!
Thanks!
Note: I need to keep the cell addresses in the master file cells so other people can follow those addresses to the feeder files, so I can't use the Evaluate formula.
This sounds like a recalculation, or non-recalcualtion, issue.
You may use this simple macro to apply F2 + Enter on the currently selected range:
Sub ApplyF2()
Selection.Value = Selection.FormulaR1C1
End Sub
Can you modify that technique to suit your needs?

I am trying to write a script that will extract hourly values from a web page table into excel

The table is in 15 minute intervals but I only need the values that are every Hour. Is there a way to tell the vba to only read the values that are timestamped to HH:00:00?
Sub GetWaterLevels()
Dim URL As String
Dim qt As QueryTable
Dim ws As Worksheet
Set ws = ActiveSheet
'Clears previously loaded data
ActiveSheet.Range("C4:D85").ClearContents
URL = "http://waterdata.quinteconservation.ca/KiWIS/KiWIS?service=kisters&type=queryServices&request=getTimeseriesValues&datasource=0&format=html&ts_id=3641042&metadata=true&md_returnfields=station_name,ts_name,ts_unitname&&period=PT10H&width=600&height=400"
'Downloads the table into excel
Set qt = ws.QueryTables.Add( _
Connection:="URL;" & URL, _
Destination:=Range("C4"))
With qt
.RefreshOnFileOpen = False
.Name = "WaterLevels"
.FieldNames = True
.WebSelectionType = xlAllTables
.Refresh BackgroundQuery:=False
End With
End Sub
I learn something new everyday. The way you get that table is amazingly fast. My skills are no where near as good as yours, but with the dilemma you have the below is the only answer I can come up with. I don't know if you can select certain rows with your method or not on the import side. I looked at webtables property but don't know enough about it. What I would do is cull the table once it is on my sheet with the following code. When I use your code to import the table it puts the active data starting on row 10. You might have to adjust that to suit your needs.
Sub sortTable()
Dim lastRow As Long, firstRow As Long, myArray1, myArray2, myCounter As Long, i As Long
' When I ran your getWaterLevels script it put the data starting on row 10
firstRow = 10
lastRow = ActiveSheet.Range("C65536").End(xlUp).Row
myCounter = 1
ReDim myArray1(1 To 1)
ReDim myArray2(1 To 1)
Application.ScreenUpdating = False
For i = firstRow To lastRow
If Range("C" & i).Value <> "" And InStr(1, Range("C" & i).Value, ":00:00.") > 0 Then
ReDim Preserve myArray1(1 To myCounter)
ReDim Preserve myArray2(1 To myCounter)
myArray1(myCounter) = Range("C" & i)
myArray2(myCounter) = Range("D" & i)
myCounter = myCounter + 1
End If
Next i
Cells.Select
With Selection
.Font.Name = "Arial"
.Font.Size = 11
.Interior.Pattern = xlNone
.Interior.TintAndShade = 0
.Interior.PatternTintAndShade = 0
End With
Range("C10:D" & lastRow).Select
Selection.ClearContents
Range("A1").Select
myCounter = 10
For i = LBound(myArray1) To UBound(myArray1)
Range("C" & myCounter).Value = myArray1(i)
Range("D" & myCounter).Value = myArray2(i)
myCounter = myCounter + 1
Next i
Application.ScreenUpdating = True
End Sub

Optimise excel VBA code - combine resident address

I have done the following 2 VBA code in excel. Main purpose is to combine multiple address rows into a single line. Problem is it takes forever to run. Is there anyway I can optimise it?
The data is as such, there is a case# for each of the customer address. The customer address can be split into multiple rows. Example: "Address row 1 - Block 56", "Address row 2 - Parry Avenue", "address row 3 - Postal code". There is a blank space between each new address.
My purpose is to combine the address into a single line, and remove the empty rows in between the case numbers eg "Block 56 Parry Avenue Postal code". There are approx 26K case numbers.
Sub test()
Dim l As Long
Dim lEnd As Long
Dim wks As Worksheet
Dim temp As String
Application.EnableEvents = False
Application.ScreenUpdating = False
Set wks = Sheets("data")
wks.Activate
lEnd = ActiveSheet.UsedRange.Rows.Count
For l = 3 To lEnd
If Not IsEmpty(Cells(l, 1)) Then
Do Until IsEmpty(Cells(l + 1, 4))
temp = Cells(l, 4).Value & " " & Cells(l + 1, 4).Value
Cells(l, 4).Value = temp
Cells(l + 1, 4).EntireRow.Delete
Loop
Else: Cells(l, 1).EntireRow.Delete
Do Until IsEmpty(Cells(l + 1, 4))
temp = Cells(l, 4).Value & " " & Cells(l + 1, 4).Value
Cells(l, 4).Value = temp
Cells(l + 1, 4).EntireRow.Delete
Loop
End If
Next l
End Sub
and the 2nd code I tried
Sub transformdata()
'
Dim temp As String
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Range("A3").Select
Do Until IsEmpty(ActiveCell) And IsEmpty(ActiveCell.Offset(1, 0))
Do Until IsEmpty(ActiveCell.Offset(1, 3))
temp = ActiveCell.Offset(, 3).Value & " " & ActiveCell.Offset(1, 3).Value
ActiveCell.Offset(, 3).Value = temp
ActiveCell.Offset(1, 3).EntireRow.Delete
Loop
ActiveCell.Offset(1, 0).EntireRow.Delete
ActiveCell.Offset(1, 0).Select
Loop
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Change the line lEnd = ActiveSheet.UsedRange.Rows.Count. Incorrect way of finding last row. You may want to see This
To delete rows where Cells(l, 1) is empty, use Autofilter. See This
Do not delete rows in a straight loop. Use a reverse loop. Or what you could do is identify the cells that you want to delete in a loop and then delete them in one go after the loop. You may want to see This
Here is a basic example.
Let's say your worksheet looks like this
If you run this code
Sub test()
Dim wks As Worksheet
Dim lRow As Long, i As Long
Dim temp As String
Application.ScreenUpdating = False
Set wks = Sheets("data")
With wks
'~~> Find Last Row
lRow = .Range("C" & .Rows.Count).End(xlUp).Row
For i = lRow To 2 Step -1
If Len(Trim(.Range("C" & i).Value)) <> 0 Then
If temp = "" Then
temp = .Range("C" & i).Value
Else
temp = .Range("C" & i).Value & "," & temp
End If
Else
.Range("D" & i + 1).Value = temp
temp = ""
End If
Next i
End With
End Sub
You will get this output
Now simply run the autofilter to delete the rows where Col D is empty :) I have already give you the link above for the same.
The code below will copy all the data into an array, consolidate it, and add it to a new worksheet. You'll need to make COLUMNCOUNT = the number of columns that contain data.
Sub TransformData2()
Const COLUMNCOUNT = 4
Dim SourceData, NewData
Dim count As Long, x1 As Long, x2 As Long, y As Long
SourceData = Range("A" & Range("D" & Rows.count).End(xlUp).Row, Cells(3, COLUMNCOUNT))
For x1 = 1 To UBound(SourceData, 1)
count = count + 1
If count = 1 Then
ReDim NewData(1 To 4, 1 To count)
Else
ReDim Preserve NewData(1 To 4, 1 To count)
End If
For y = 1 To UBound(SourceData, 2)
NewData(y, count) = SourceData(x1, y)
Next
x2 = x1 + 1
Do
NewData(4, count) = NewData(4, count) & " " & SourceData(x2, 4)
x2 = x2 + 1
If x2 > UBound(SourceData, 1) Then Exit Do
Loop Until IsEmpty(SourceData(x2, 4))
x1 = x2
Next
ThisWorkbook.Worksheets.Add
Range("A1").Resize(UBound(NewData, 2), UBound(NewData, 1)).Value = WorksheetFunction.Transpose(NewData)
End Sub