Removing duplicates, keeping information and summarizing VBA - excel

So I am trying to handle some data through VBA and I have a hard time figuring out how to do this the correct and less time consuming way when the data is getting handled.
I have an excel sheet that contains data from A:V with dynamic rows and including headers. But there is a lot of the data I do not need for any reasons.
So, my task is to take column K, P, Q, T, U, and V, and find all the unique combinations/values from this. Then I want to take this unique value and summarize what is in Column O. Afterwards I want to print this to a new sheet, where I have printed all the columns that made the combination. It could look like this:
HeadK
HeadP
HeadQ
HeadT
HeadU
HeadV
HeadO
Proj1
Actual
12
2022
Constrained
5
Proj2
Actual
12
2022
Constrained
1
Proj1
Actual
12
2022
Constrained
3
Proj2
Actual
5
2022
Constrained
10
The idea is just to tell that there can be a lot of combinations with so many columns. But in this case line 1 and 3 could be contained in 1 row, and instead present 8 in head0.
Can anybody help me with this?
I have actually tried some code from chatgpt, but can't get it to work correctly. I know it is not allowed to answer with it, but guess this is my own post, so I can admit my own mistakes....
Sub SummarizeData()
Dim ws As Worksheet
Dim dataRange As Range
Dim uniqueValues As Collection
Dim cell As Range
Dim uniqueValue As Variant
Dim summaryArray() As Variant
Dim summaryIndex As Long
' Define the worksheet
Set ws = ThisWorkbook.Sheets("TimeRegistrations_Billable")
' Define the data range
Set dataRange = ws.Range("K2:V" & ws.Range("K" & ws.Rows.Count).End(xlUp).Row)
' Create a collection to store unique values
Set uniqueValues = New Collection
' Iterate over the data range
For Each cell In dataRange.Columns(1).Cells
uniqueValue = cell.Value & cell.Offset(0, 6).Value & cell.Offset(0, 12).Value & cell.Offset(0, 13).Value & cell.Offset(0, 14).Value
On Error Resume Next
uniqueValues.Add uniqueValue, uniqueValue
On Error GoTo 0
uniqueValues.Add cell.Value, cell.Value & cell.Offset(0, 6).Value & cell.Offset(0, 12).Value & cell.Offset(0, 13).Value & cell.Offset(0, 14).Value & "K"
uniqueValues.Add cell.Offset(0, 10).Value, cell.Value & cell.Offset(0, 6).Value & cell.Offset(0, 12).Value & cell.Offset(0, 13).Value & cell.Offset(0, 14).Value & "T"
uniqueValues.Add cell.Offset(0, 11).Value, cell.Value & cell.Offset(0, 6).Value & cell.Offset(0, 12).Value & cell.Offset(0, 13).Value & cell.Offset(0, 14).Value & "U"
Next cell
' Create an array to store the summarized data
ReDim summaryArray(1 To uniqueValues.Count, 1 To 5)
summaryIndex = 0
' Iterate over the unique values
For Each uniqueValue In uniqueValues
summaryIndex = summaryIndex + 1
summaryArray(summaryIndex, 1) = uniqueValue
summaryArray(summaryIndex, 2) = WorksheetFunction.SumIf(dataRange.Columns(15), uniqueValue, dataRange.Columns(15))
summaryArray(summaryIndex, 3) = uniqueValue & "K"
summaryArray(summaryIndex, 4) = uniqueValue & "T"
summaryArray(summaryIndex, 5) = uniqueValue & "U"
Next uniqueValue
' Add the summarized data to a new worksheet
With ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
.Name = "Tester"
.Range("A1").Resize(uniqueValues.Count, 5).Value = summaryArray
End With
End Sub

So I actually have found 1 way to do it, I just need to remove all the duplicates in column 23 though. But this takes like ages to run, when you have 500k lines.
Don't know if this code makes more sense.
But when the duplicates in data1 column 23 has been removed, I have the data I want as the end gold (and more columns included which is not needed).
Sub uniquevalues()
Dim data1 As Variant, data2 As Variant
Dim lastRowTRB As Long, lastRowdata1 As Long
Dim timer As Double
Dim i As Long, k As Long
lastRowTRB = Worksheets("TimeRegistrations_Billable").Cells(Rows.count, "A").End(xlUp).row
data1 = Worksheets("TimeRegistrations_Billable").Range("A1:X" & lastRowTRB).Value
For i = 2 To lastRowTRB
If i > UBound(data1, 1) Then Exit For
data1(i, 23) = data1(i, 11) & data1(i, 16) & data1(i, 17) & data1(i, 20) & data1(i, 21) & data1(i, 22)
Next i
data2 = data1
For i = 2 To lastRowTRB
If i > UBound(data1, 1) Then Exit For
timer = 0
For k = 2 To lastRowTRB
If k > UBound(data2, 1) Then Exit For
If data2(i, 23) = data2(k, 11) & data2(k, 16) & data2(k, 17) & data2(k, 20) & data2(k, 21) & data2(k, 22) Then
timer = timer + data1(k, 15)
End If
Next k
data1(i, 24) = timer
Next i
With ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.count))
.Name = "Tester"
.Range("A1").Resize(lastRowTRB, 24).Value = data1
End With

Related

For Each loop on filtered data returning 0 results, no errors

I need to generate a sheet of values out of a database between dates that the user selects. The date is in column 2 of the database, but I need the whole row for every date in this range. I got some advice to use a For Each instead to more easily use the SpecialCells(xlCellTypeVisible). While I am no longer getting any errors I also get no data in my product worksheet. Could someone tell me why I am not returning data?
Sub Generate()
Dim g As Integer
Dim h As Integer
Dim datemin As String
Dim datemax As String
datemin = CDbl(CDate(Sheets("start").Cells(15, 8)))
datemax = CDbl(CDate(Sheets("start").Cells(15, 9)))
Worksheets("Database").Range("A1").AutoFilter Field:=10, Criteria1:=">=" & datemin, _
Operator:=xlAnd, Criteria2:="<=" & datemax
g = 0
For Each Row In Worksheets("database").Range("A1")
g = g + 1
If Cells(g, 1).SpecialCells(xlCellTypeVisible) = True And Cells(g, 1) <> "" Then
Sheets("product").Activate
Dim NextRow As Long
NextRow = Application.WorksheetFunction.CountA(Range("A:A")) + 10
'fill KPI
Cells(NextRow, 1) = Format(Sheets("database").Cells(g, 1), "mm/dd/yyyy") 'Date1
Cells(NextRow, 2) = Format(Sheets("database").Cells(g, 2), "mm/dd/yyyy") 'Date2
Cells(NextRow, 3) = Sheets("database").Cells(g, 3) 'value1
Cells(NextRow, 4) = Sheets("database").Cells(g, 4) 'value2
Cells(NextRow, 6) = Sheets("database").Cells(g, 5) 'value3
Cells(NextRow, 9) = Sheets("database").Cells(g, 8) 'comment
Cells(NextRow, 13) = Sheets("database").Cells(g, 6) 'person
Else
Exit For
End If
Next
End Sub
You are only 'looping' through one cell - A1.
If you want to use a loop for this try looping through all the rows on the database and checking if they are visible or not.
If they are visible then copy the relevant data to the other sheet.
Sub Generate()
Dim rngDst As Range
Dim rngSrc As Range
Dim datemin As String
Dim datemax As String
Dim g As Integer
Dim h As Integer
datemin = CDbl(CDate(Sheets("start").Cells(15, 8)))
datemax = CDbl(CDate(Sheets("start").Cells(15, 9)))
Worksheets("Database").Range("A1").AutoFilter Field:=10, Criteria1:=">=" & datemin, _
Operator:=xlAnd, Criteria2:="<=" & datemax
Set rngSrc = Worksheets("Database").Range("A2")
Set rngDst = Worksheets("Product").Range("A11")
Do
If Not rngSrc.EntireRow.Hidden And rngSrc.Value <> "" Then
'fill KPI
rngDst.Value = Format(rngSrc.Value, "mm/dd/yyyy") 'Date1
rngDst.Offset(, 1).Value = Format(rngSrc.Offset(, 1).Value, "mm/dd/yyyy") 'Date2
rngDst.Offset(, 2).Value = rngSrc.Offset(, 2).Value 'value1
rngDst.Offset(, 3).Value = rngSrc.Offset(, 3).Value 'value2
rngDst.Offset(, 5).Value = rngSrc.Offset(, 4).Value 'value3
rngDst.Offset(, 8).Value = rngSrc.Offset(, 7).Value 'comment
rngDst.Offset(, 12).Value = rngSrc.Offset(, 5).Value 'person
Set rngDst = rngDst.Offset(1, 0)
End If
Set rngSrc = rngSrc.Offset(1, 0)
Loop Until rngSrc = ""
End Sub

Excel: How do I 'gather' values to display in another cell

I have two columns, Column A has a set of a few standard values and column B has all unique values. I'm only just experimenting with more complex ways of compiling data than the beginner level so I'm a bit at a loss.
I need to either have a lookup or create a macro that will list only the values in A (once each) but also display which values in B correspond to those in A
for example
A | B
va1|abc
va1|bcd
Va2|xyz
va3|zab
will show (in a single cell) the following
va1: abc, bcd
va2: xyz
va3: zab
Please help!
Option Explicit
Sub Test()
Dim i As Long, j As Long, k As Long
k = 1
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
If Application.CountIf(Range("C:C"), Cells(i, 1).Value) = 0 Then
Cells(k, 3).Value = Cells(i, 1).Value
For j = 1 To Cells(Rows.Count, 1).End(xlUp).Row
If Cells(j, 1).Value = Cells(k, 3).Value And _
InStr(Cells(k, 4).Value, Cells(j, 2).Value) = 0 Then
If Cells(k, 4).Value = "" Then
Cells(k, 4).Value = Cells(j, 2).Value
Else
Cells(k, 4).Value = Cells(k, 4).Value & ", " & Cells(j, 2).Value
End If
End If
Next j
k = k + 1
End If
Next i
For i = 1 To Cells(Rows.Count, 3).End(xlUp).Row
Cells(i, 3).Value = Cells(i, 3).Value & ": " & Cells(i, 4).Value
Cells(i, 4).ClearContents
Next i
End Sub
Edited for single cell
In case your requirement is to "have the grouped data", and not exactly "have one single string per A", you can do this with a "pivot table" putting A and B in the row labels, like in the following picture:

Formatting the first two rows of data retrieved from multiple worksheets in to a combined view worksheet

I have an excel workbook that consists of 5 worksheets that contain data and a 6th worksheet with a button that when clicked retrieves the data from the other 5 sheets to provide a combined view.
The data in the other 5 sheets is slightly different from each other, except for a few common columns so, I have to show the data in the combined view as one under the other with the country in row 1 and the headings in row 2 in bold text if possible for the data retrieved in each sheet.
I am able to run the macro via button to retrieve the data but I am not able to pull all the data in as required but for some reason, my code for setting the rows 1 and 2 for each sheet to bold is not working (code below shows me trying to get the first row to be set to bold).
One thing to keep in mind is that the amount of data on each sheet (the number of rows) may differ each time the macro is run.
Appreciate any help.
Option Compare Text
Sub OptionCompareText()
End Sub
Sub SearchMultipleSheets()
Dim arr(999, 14) As Variant, r As Range
Dim ws As Worksheet, i As Integer, s As String
With Sheets(1)
's = Range("b10").Value
.Range("a13").Resize(.UsedRange.Rows.Count, UsedRange.Columns.Count).ClearContents
End With
For Each ws In Worksheets
If ws.Name <> Sheets(1).Name Then
With ws
For Each r In .Range("a1", .Range("a" & .Rows.Count).End(xlUp))
If r.Value & r.Offset(0, 1).Value & r.Offset(0, 2).Value & r.Offset(0, 3).Value & r.Offset(0, 4).Value _
& r.Offset(0, 5).Value & r.Offset(0, 6).Value & r.Offset(0, 7).Value & r.Offset(0, 8).Value _
& r.Offset(0, 9).Value & r.Offset(0, 10).Value & r.Offset(0, 11).Value & r.Offset(0, 12).Value & r.Offset(0, 13).Value _
Like "*" & s & "*" Then
'arr(i, 0) = ws.Name
arr(i, 0) = r.Value
arr(i, 1) = r.Offset(0, 1).Value
arr(i, 2) = r.Offset(0, 2).Value
arr(i, 3) = r.Offset(0, 3).Value
arr(i, 4) = r.Offset(0, 4).Value
arr(i, 5) = r.Offset(0, 5).Value
arr(i, 6) = r.Offset(0, 6).Value
arr(i, 7) = r.Offset(0, 7).Value
arr(i, 8) = r.Offset(0, 8).Value
arr(i, 9) = r.Offset(0, 9).Value
arr(i, 10) = r.Offset(0, 10).Value
arr(i, 11) = r.Offset(0, 11).Value
arr(i, 12) = r.Offset(0, 12).Value
arr(i, 13) = r.Offset(0, 13).Value
i = i + 1
End If
Next r
End With
End If
Next ws
With Sheets(1)
.Range("a13").Resize(i, 14).Value = arr
For Each ws In ActiveWorkbook.Worksheets
With ws.Rows(1)
.Font.Bold = True
End With
Next ws
End With
End Sub

VBA and passing values

I'm trying to compare data between two worksheets. Each Worksheet has three column: A is a concatenation of a Customer and a SKU, B is the sales volume and C is for measuring volume discrepancies. I aim to do two things, check Sheet1 for SKUs that are not in Sheet2 and then, if SKUs match on both sheets, check their volume for quantity differences. If Sheet 1 has a SKU not in Sheet2, I want the record highlighted. I've accomplished this in a primitive way, the entire row gets highlighted. I am, however, having trouble getting the code to check volumes if the Customer & SKU match. I was hoping VBA would retain the values of the cells it was checking, where have I gone wrong and what is the proper implementation? Sorry for being such a n00b.
Sub Again()
Dim lastRow As Integer
Dim rng As Range
lastRow = Sheets("Sheet1").Range("A65000").End(xlUp).Row
For i = 1 To lastRow
Set rng = Sheets("sheet2").Range("A:A").Find(Sheets("Sheet1").Cells(i, 1))
If rng Is Nothing Then
Sheets("Sheet1").Cells(i, 3) = "Item not in sheet2"
Sheets("Sheet1").Cells(i, 1).EntireRow.Interior.Color = vbRed
ElseIf Not rng Is Nothing Then
If Sheets("sheet1").Cells(i, 2).Value - Sheets("sheet2").Cells(i, 2).Value < -5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet2 reports " & Sheets("sheet1").Cells(i, 2).Value - Sheets("sheet2").Cells(i, 2).Value & " more units of volume."
ElseIf Sheets("sheet1").Cells(i, 2) - Sheets("sheet2").Cells(i, 2) > 5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet1 reports " & Sheets("sheet1").Cells(i, 2) - Sheets("sheet2").Cells(i, 2) & " more units of volume."
Else: Sheets("sheet1").Cells(i, 3) = "No or insignificant discrepancy"
End If
End If
Next
End Sub
I think you need to reuse rng like this:
rng.offset(2,0).value
in place of:
Sheets("sheet2").Cells(i, 2).Value
Because all your currently doing is assuming that the matching cell is in exactly the same row as in sheet1.
Your code should then look something like this:
Sub Again()
Dim lastRow As Integer
Dim rng As Range
lastRow = Sheets("Sheet1").Range("A65000").End(xlUp).Row
For i = 1 To lastRow
Set rng = Sheets("sheet2").Range("A:A").Find(Sheets("Sheet1").Cells(i, 1))
If rng Is Nothing Then
Sheets("Sheet1").Cells(i, 3) = "Item not in sheet2"
Sheets("Sheet1").Cells(i, 1).EntireRow.Interior.Color = vbRed
ElseIf Not rng Is Nothing Then
If Sheets("sheet1").Cells(i, 2).Value - rng.offset(0, 2).Value < -5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet2 reports " & Sheets("sheet1").Cells(i, 2).Value - rng.offset(0, 2).Value & " more units of volume."
ElseIf Sheets("sheet1").Cells(i, 2) - rng.offset(0, 2).Value > 5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet1 reports " & Sheets("sheet1").Cells(i, 2) - rng.offset(0, 2).Value & " more units of volume."
Else: Sheets("sheet1").Cells(i, 3) = "No or insignificant discrepancy"
End If
End If
Next
End Sub
Variables. ...If I understand your questions correctly.
dim myString as String
dim myFloat as Float

i am trying to write an if statement for a specific range of cells but i got the same formula applied to that range.

Sub RebateCalculation()
For x = 2 To 400
If Cells(x, 29) = (-0.2) Then
Range(Cells(x, 25), Cells(x, 25)).Formula = "=0.06*Q4-Q4+O4/M4"
ElseIf Cells(x, 29) = (-0.333333333333333) Then
Range(Cells(x, 25), Cells(x, 25)).Formula = "=0.05*Q4-Q4+O4/M4"
ElseIf Cells(x, 29) = (-1.4) Then
Range(Cells(x, 25), Cells(x, 25)).Formula = "0.05 * Q4 - Q4 + O4 / M4"
Else
Cells(x, 25) = ""
End If
Next x
End Sub
Here is a simple example. to see it work enter 1 to 10 in the first 10 rows of column A and then run it.
I have used FormulaR1C1 because it allows you to easily loop through and modify formula depending on a variable. As you can see you make sure the "R1C1" is entered as a complete string reference to a cell and it can be made up of a few strings and variables "R"& rowNumber & "C" & columnNumber
Sub addEquation()
For i = 1 To 10
If Cells(i, 1).Value = 1 Then
Cells(i, 2).FormulaR1C1 = "=10*R" & i & "C1"
Else
Cells(i, 2).FormulaR1C1 = "=500*R" & i & "C1"
End If
Next i
End Sub
The other option as is instead of specifying all three formula as fixed strings "=0.06*Q4-Q4+Q4/M4" try "=0.06*" & Cell & "-" & cell & "+" & cell & "/" & cell2 where you increment the cell string in in each for loop

Resources