subtotaling on live data macro - excel

I have created a data table through Sharperlight reporting thats generates its results into excel as shown below:-
What I want to do is develop a macro that will subtotal all categories for the data. There is no determined length size of the table other than it will always be columns G - J.
This way my hope is when a user refreshes the table using the menu on the side they will then be able to run a macro to get a quick one line total for each category.
Can anyone help with this???

Right click on the sheet1 tab > View Code
paste this code
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 4 Then
If Target.Row = 4 Or Target.Row = 5 Or Target.Row = 6 Then Totals
End If
End Sub
then add a module right click Sheet1 in the Project Explorer in the VBE window and Insert > Module
then pate this code
Sub Totals()
Range("C10:D" & Range("C10:C" & Rows.Count).End(xlDown).Row).ClearContents
Dim startAtRow As Long
startAtRow = 10 ' Set starting row
Dim lr As Long, i As Long, j As Long
lr = Range("J" & Rows.Count).End(xlUp).Row
ReDim arr(lr - 4) As String
For i = 5 To lr
arr(i - 5) = Range("J" & i).Value
Next i
Dim arr2() As String
arr2 = arr
RemoveDuplicate arr
For i = LBound(arr) To UBound(arr) - 1
Range("C" & (i + startAtRow)).Value = arr(i)
For j = LBound(arr2) To UBound(arr2) - 1
If arr(i) = arr2(j) Then
Range("D" & (i + startAtRow)).Value = Range("D" & i + startAtRow).Value + Range("I" & (j + 5)).Value
End If
Next j
Next i
End Sub
Private Sub RemoveDuplicate(ByRef StringArray() As String)
Dim lowBound$, UpBound&, A&, B&, cur&, tempArray() As String
If (Not StringArray) = True Then Exit Sub
lowBound = LBound(StringArray): UpBound = UBound(StringArray)
ReDim tempArray(lowBound To UpBound)
cur = lowBound: tempArray(cur) = StringArray(lowBound)
For A = lowBound + 1 To UpBound
For B = lowBound To cur
If LenB(tempArray(B)) = LenB(StringArray(A)) Then
If InStrB(1, StringArray(A), tempArray(B), vbBinaryCompare) = 1 Then Exit For
End If
Next B
If B > cur Then cur = B: tempArray(cur) = StringArray(A)
Next A
ReDim Preserve tempArray(lowBound To cur): StringArray = tempArray
End Sub
Now every time user is changing the values of D4,D5,D6 your results should update. The categories will be displayed starting at C10 down, and the totals at D10 down. Looks like this ( sample version )

Related

Need help in speeding up a looping macro

I am using a Macro to identify same details entered (in Column B, C and D) for multiple students (Column A).
This macro is working fine on approx 10,000 rows. But when I use it on full database ex: 1,00,000 rows it just got hanged.
Any help to in speeding up this macro will be very helpful.
`
Option Explicit
Sub test()
Dim lRow As Long, i As Long, j As Long
Dim c As Integer
Dim students() As Variant
Dim results() As Variant
lRow = Cells(Rows.Count, 1).End(xlUp).Row
ReDim results(lRow - 1)
students = Range("A1:D" & lRow).Value
For i = 2 To lRow
found = False
For j = 2 To lRow
If students(i, 1) = students(j, 1) Then GoTo skipStudent
For c = 1 To 4
If students(j, c) = "-" Or students(i, c) = "-" Then GoTo skipColumn
If students(i, c) = students(j, c) Then
results(i - 1) = results(i - 1) & "Same " & students(1, c) & " information with " & students(j, 1) & vbCrLf
End If
skipColumn:
Next
skipStudent:
Next
Next
Application.ScreenUpdating = False
For i = 2 To lRow
Cells(i, 5).Value = results(i - 1)
Next
Application.ScreenUpdating = True
End Sub
`

How to increment Numbers With Decimals and Restart Numbering When Number Changes?

I want to increment the decimal part of a number and restart numbering every time the number changes as below
1.00
1.01
1.02
1.03
1.04
1.05
2.00 'Restart With 2
2.01
3.00 'Restart With 3
3.01
3.02
3.03
I used the following Code
Sub AutoNumberDecimals()
Dim Rng, C As Range
Dim Lrow As Long
Dim i As Integer
Lrow = Cells(Rows.Count, 1).End(xlUp).Row
Set Rng = Worksheets("Union").Range("A2:A" & Lrow)
For Each C In Rng.Cells
If C.Value = "" And C.Offset(0, 1).Value = "" Then
C.Offset(1, 0).Value = C.Value + 0.01
Next C
End Sub
But It did not work
Appreciate your help
Thanks, Regards
I wrote this code. Make sure to add it in Sheet1 module (or similar sheet). It reacts when you enter a number in column 1 and it renumbers all numbers in that column. If you enter 1, it shows 1.00... if you enter 1 again, it will show 1.01. If you enter 2 you will have 2.00 etc...
Private ChangingValues As Boolean
Private Sub RenumFirstColumn()
Dim RowNo As Integer
Dim Major As Integer
Dim Minor As Integer
Dim CurrentValue As String
RowNo = 1
Major = 1
Minor = 0
Do
CurrentValue = CStr(Cells(RowNo, 1).Value)
If Int(Val(Left(CurrentValue, 1))) = Major Then
CurrentValue = CStr(Major) & "." & Format(Minor, "00")
Minor = Minor + 1
If Minor > 99 Then
MsgBox "To high value (> X.99)"
Exit Sub
End If
Else
Major = Val(Left(CurrentValue, 1))
Minor = 0
CurrentValue = CStr(Major) & "." & Format(Minor, "00")
Minor = Minor + 1
End If
Cells(RowNo, 1).NumberFormat = "#"
Cells(RowNo, 1).Value = CurrentValue
RowNo = RowNo + 1
Loop Until IsEmpty(Cells(RowNo, 1))
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 And ChangingValues = False Then
ChangingValues = True
RenumFirstColumn
ChangingValues = False
End If
End Sub
Hope it was what you were looking for
Try the next code, please. It uses maxIncr variable to set a maximum incrementing times:
Sub IncrementingRoots()
Dim sh As Worksheet, lastR As Long, maxIncr As Long
Dim NrI As Long, i As Long, j As Long
Set sh = ActiveSheet: maxIncr = 7
lastR = sh.Range("A" & Rows.count).End(xlUp).Row
For i = 2 To lastR + maxIncr
If sh.Range("A" & i).Value <> "" Then
NrI = sh.Range("A" & i).Value
For j = 1 To maxIncr
If sh.Range("A" & i + j).Value = Empty Then
sh.Range("A" & i + j).Value = sh.Range("A" & i + j - 1).Value + 0.01
Else
i = j + i - 1: Exit For
End If
Next
End If
If i > lastR Then Exit For
Next i
End Sub
And the next code is yours adapted to work. But impossible to procress the last number in the range, too, without something more (like maxIncr in my above code)...
Sub AutoNumberDecimals()
Dim sh As Worksheet, Rng As Range, C As Range, Lrow As Long, i As Long
Set sh = ActiveSheet 'Worksheets("Union")
Lrow = sh.cells(Rows.count, 1).End(xlUp).Row
Set Rng = sh.Range("A2:A" & Lrow)
For Each C In Rng.cells
If C.Value = "" And (C.Offset(1, 0).Value <> _
Int(C.Value Or C.Offset(1, 0).Value = "")) Then
C.Value = C.Offset(-1, 0).Value + 0.01
End If
Next C
End Sub
This uses DataSeries and NumberFormat to fill the cells.
This creates a random board, and isn't necessary to the main code.
Cells.Clear
Cells(1, 1) = 1 ' creates a random board
x = 2
For i = 2 To 20
If Rnd() > 0.8 Then
Cells(i, 1) = x
x = x + 1
End If
Next i
Cells(21, 1) = 0 ' terminates entries
Note that rather than determine the row column length using code, I have preset it to 21, although you can use the terminating 0.00 value to define a column length.
The main code:
Range("a:a").NumberFormat = "0.00"
For i = 1 To 21 ' loops through range
j = 0 ' finds local range
If Cells(i, 1) <> "" And Cells(i, 1) > 0 Then
Do
j = j + 1
Loop While Cells(i + j, 1) = ""
End If
Range(Cells(i, 1), Cells(i + j - 1, 1)).DataSeries Type:=xlLinear, Step:=0.01
i = i + j ' jumps to next entry
Next i
Each cell is formatted into the desired style. Then the loop finds a non-empty cell, and determines the associated local subrange by checking if the next cell down is empty or not, and continues until it isn't. Then the subrange is formatted using DataSeries with a Step of 0.01.
Ref:
https://learn.microsoft.com/en-us/office/vba/api/excel.range.dataseries

joining all cell value between ascending range

I am trying to figure out how to join every cell (normal text) in the D column between the range I have set up in the A column. While searching I came across variations of the concatenate, textjoin and other functions but could not seem to find the right option.
There are around 8000 values in my file(ID value in column A) so it should be automatically filled and not manual. since it would take weeks to complete...
i've added a visual representation of the problem
The solution would be to have all cells selected in column D between the value '1' and '2' in column A and joined togheter in the E column in the row where the the cell in the A column isn't blank.
I hope someone can help me with this problem.
Try this code, please. It should be very fost, using arrays and returns the built strings at once at the end:
Sub testJoinBetweenLimits()
Dim sh As Worksheet, arrInit As Variant, arrFin As Variant
Dim strInit As String, i As Long, j As Long, refRow As Long
Set sh = ActiveSheet 'use here your sheet
arrInit = sh.Range("A2:D" & sh.Range("D" & Cells.Rows.Count).End(xlUp).Row).value
ReDim arrFin(1 To 1, 1 To UBound(arrInit, 1))
For i = 1 To UBound(arrInit, 1)
If arrInit(i, 1) <> "" Then strInit = arrInit(i, 4): refRow = i: j = i + 1
Do While arrInit(j, 1) = ""
If arrInit(j, 4) <> "" Then
strInit = strInit & ", " & arrInit(j, 4)
Else
arrFin(1, j) = Empty
End If
j = j + 1
If j >= sh.Range("D" & Cells.Rows.Count).End(xlUp).Row Then
arrFin(1, refRow) = strInit
ReDim Preserve arrFin(1 To 1, 1 To refRow)
GoTo Ending
End If
Loop
i = j - 1
arrFin(1, refRow) = strInit: strInit = "": j = 0
Next i
Ending:
sh.Range("E2").Resize(UBound(arrFin, 2), 1).value = WorksheetFunction.Transpose(arrFin)
End Sub

Expand Rows Based on Column

I am creating hierarchies and need to outline them in the format on the right-hand side. It would be a lot easier if I could simply outline the hierarchy in one column and automatically have it expand (left -> right in the sample).
A few considerations:
Within the first column, the start of a new hierarchy will always be the value 'A'
Hierarchies can range from 2-10 children in length
Any thoughts?
Type the letters in column A only, start each new sequence with the word HEADER. Then run the macro and the expansions should be created.
Sub expand()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim cell As Range, cellHeader As Range
Dim irow As Integer, i As Integer
Dim iCount As Integer, iLast As Long
' find last row in col A
iLast = ws.Range("A" & Rows.Count).End(xlUp).Row
'scan down the sheet
For Each cell In ws.Range("A1:A" & iLast)
If UCase(cell) = "DIRECT" Then
' remember the header line
Set cellHeader = cell
With cellHeader
.BorderAround xlContinuous
.Font.Bold = True
End With
ElseIf Len(cell) > 0 Then
cell.BorderAround xlContinuous
' start of sequence
If cell = "A" Then
irow = 1
iCount = 0
End If
' add header value
With cellHeader.Offset(0, irow)
.Value = "L" & irow
.Font.Bold = True
.BorderAround xlContinuous
End With
' copy cell diagonally upwards
If irow > 1 Then
For i = 1 To irow - 1
cell.Offset(-i, i) = cell.Value
cell.Offset(-i, i).BorderAround xlContinuous
Next
End If
' check max children
iCount = iCount + 1
If iCount > 10 Then
MsgBox "Children count > 10", vbCritical, "Error"
Exit Sub
End If
irow = irow + 1
End If
Next
MsgBox "Expansion Complete", vbInformation
End Sub
You do not answer my questions and I cannot wait, anymore...
Please test the next code, which works based on the thowe assumptions: Your hierarchies in discussion have all the time a kind of header (Direct in column A:A and L1 in B:B). This, or an empty row sets the bottom part of the hierarchy.
Here's the code:
Sub HierarchyArrangeMultipleR()
Dim sh As Worksheet, i As Long, j As Long, lastR As Long, lastH As Long
Dim arrI As Variant, arrTr As Variant, colN As Long, k As Long, h As Long
Set sh = ActiveSheet 'please, use here your worksheet
lastR = sh.Range("A" & sh.Rows.count).End(xlUp).Row
For k = 1 To lastR
If lastH > 0 Then k = lastH + 1
If k >= lastR Then Exit For
Start:
If sh.Range("A" & k).Value = "Direct" And sh.Range("B" & k).Value = "L1" Then
For i = 1 To 10
If sh.Range("A" & k + i).Value = "Direct" Or _
sh.Range("A" & k + i).Value = Empty Then
lastH = k + i - 1: Exit For
End If
Next i
For h = 3 To lastH - k
sh.Cells(k, h) = "L" & h - 1
Next h
Else
k = k + 1: GoTo Start
End If
arrI = sh.Range("A" & k + 1 & ":A" & lastH).Value
ReDim arrTr(1 To UBound(arrI) - 1)
colN = 1
For i = k To lastH - 2
For j = 1 To UBound(arrTr) 'lastH - i + k - 2
arrTr(j) = arrI(j, 1)
Next j
colN = colN + 1
sh.Range(sh.Cells(k + 1, colN), sh.Cells(lastH + 1 - colN, colN)).Value = WorksheetFunction.Transpose(arrTr)
Next i
Erase arrTr
Next k
End Sub

Excel VBA to loop and find specific range and concatenate 2 cell values and delete empty cell

I am trying to identify a specific range in column-A and concatenate two cells within the specific range and delete the empty cell. I have been successful in putting a code together and it does the job very well. But, I don't know how to loop it to identify next range. Any help would be appreciated.
As per below image and code, First, I am finding and selecting a range between two (MCS) in column-A with a condition that, if the rows are more than 8 between two MCS. Then I am concatenating first 2 cells immediately after MCS and delete the empty row.
The below code works well for first range but I am unable to loop to identify next range from row 22 to 32 and perform concatenations.
I dont know how to loop in column-A and select ranges and concatenate. Any help would be much appreciated. Thanks
Sub MergeStem()
Dim findMCS1 As Long
Dim findMCS2 As Long
Dim myCount As Integer
Dim myStems As Long
Dim mySelect As Range
Dim c As Range
findMCS1 = Range("A:A").Find("MCS", Range("A1")).Row
findMCS2 = Range("A:A").Find("MCS", Range("A" & findMCS1)).Row
myCount = Range("A" & findMCS1 + 1 & ":A" & findMCS2 - 1).Cells.Count
Range("B1").Value = myCount
MsgBox "Number of rows =" & myCount
Set mySelect = Selection
If myCount > 8 Then
myStems = Range("A" & findMCS1 + 2 & ":A" & findMCS2 - 9).Select
Set mySelect = Selection
For Each c In mySelect.Cells
If firstcell = "" Then firstcell = c.Address(bRow, bCol)
sArgs = sArgs + c.Text + " "
c.Value = ""
Next
Range(firstcell).Value = sArgs
End If
Columns("A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Application.ScreenUpdating = True
End Sub
Can you try this? Ordinarily, Find would be the way to go but because you are deleting rows it's hard to keep track of which cells you've found.
Sub x()
Dim r As Long, n1 As Long, n2 As Long
With Range("A1", Range("A" & Rows.Count).End(xlUp))
For r = .Count To 1 Step -1
If .Cells(r).Value = "MCS" Then
If n1 = 0 Then
n1 = .Cells(r).Row
Else
n2 = .Cells(r).Row
End If
If n1 > 0 And n2 > 0 Then
If n1 - n2 > 9 Then
.Cells(r + 1).Value = .Cells(r + 1).Value & .Cells(r + 2).Value
'.Cells(r + 2).EntireRow.Delete
'Call procedure to delete row
End If
n1 = n2
n2 = 0
End If
End If
Next r
End With
End Sub

Resources