Modifying a sub that combines and sums duplicate rows - excel

If this sub finds finds matching values in column A, it will merge those two values into one row, and then sum columns B & C into run row.
I've been trying to change it so that for this to happen, it needs to find a match in columns A & B, then C & D will be summed.
For example:
A A 5 5
A A 5 5
A B 6 1
Will Become
A A 10 10
A B 6 1
Sub Consolidate()
Application.ScreenUpdating = False
Dim s As Worksheet, last_row As Long
Dim row As Long
Dim col As Integer, v, m
Set s = Worksheets("Sheet12")
s.Activate
last_row = s.Cells(s.rows.Count, 1).End(xlUp).row 'find the last row with data
For row = last_row To 3 Step -1
v = s.Cells(row, "A").Value
m = Application.Match(v, s.Columns("A"), 0) 'find first match to this row
If m < row Then 'earlier row?
'combine rows `row` and `m`
s.Cells(m, "B").Value = s.Cells(m, "B").Value + s.Cells(row, "B").Value
s.Cells(m, "C").Value = s.Cells(m, "C").Value + s.Cells(row, "C").Value
s.rows(row).Delete
End If 'matched a different row
Next row
End Sub

Slight modification using a dictionary:
Sub Consolidate()
Application.ScreenUpdating = False
Dim s As Worksheet, last_row As Long
Dim row As Long, dict As Object, k As String, m As Long
Set dict = CreateObject("scripting.dictionary") 'for tracking A+B vs first row occurence
Set s = Worksheets("Sheet12")
s.Activate
last_row = s.Cells(s.Rows.Count, 1).End(xlUp).row 'find the last row with data
'map all the A+B combinations to the first row they occur on
For row = 3 To last_row
k = s.Cells(row, "A").Value & "~~" & s.Cells(row, "B").Value
If Not dict.exists(k) Then dict.Add k, row
Next row
For row = last_row To 3 Step -1
k = s.Cells(row, "A").Value & "~~" & s.Cells(row, "B").Value
m = dict(k) 'find first match to this row from the dictionary
If m < row Then 'earlier row?
'combine rows `row` and `m`
s.Cells(m, "C").Value = s.Cells(m, "C").Value + s.Cells(row, "C").Value
s.Cells(m, "D").Value = s.Cells(m, "D").Value + s.Cells(row, "D").Value
s.Rows(row).Delete
End If 'matched a different row
Next row
End Sub

Related

Trouble formatting code to meet my conditions

I've been trying to re-work this code I found to combine and sum rows in a sheet.
I have a sheet with values in columns columns A-G. And a Dynamic number of rows.
If an exact duplicate is found in column D, I want to add (sum) the "column G" and "column H" values from the duplicate row, with the "G" and "H" values from the original row. With the result being in the original row.
For all other columns, I want the duplicate row to overwrite the original. (Or, overwrite if the exact same, and place next to the original value in the same cell if different, but this is beyond my knowledge.)
To clarify, the code will loop through column 'D' until it finds duplicate values. It will then delete the row of this duplicate value, after copying/pasting its values over those of the original. Except for "G" and "H", where it will sum its values with the original rows "G" and "h".
ie.
June 1
A
-----
1234
Walmart
6
7
June 2
B
BA
1234
Walmart
4
4
Would turn into
June 2
B
BA
1234
Walmart
10
11
In place of the original, for all duplicate (column "D") rows in the worksheet.
Thanks for any input.
This code I've been trying to change: works for 4 columns where column A is the ID as opposed to column D, and doesn't include the sum condition. I'm having trouble fitting it to my conditions. Specifically, why is the Cl range 'B' when this range isn't consequential, and what format the offset follows.
Sub mergeRows()
Dim Dic As Object: Set Dic = CreateObject("Scripting.Dictionary")
Dic.Comparemode = vbTextCompare
Dim Cl As Range, x$, y$, i&, Key As Variant
For Each Cl In Range("B2:B" & Cells(Rows.Count, "B").End(xlUp).Row)
x = Cl.Value & "|" & Cl.Offset(, 1).Value
y = Cl.Offset(, 2).Value
If Not Dic.exists(x) Then
Dic.Add x, Cl.Offset(, -1).Value & "|" & y & "|"
ElseIf Dic.exists(x) And Not LCase(Dic(x)) Like "*|" & LCase(y) & "|*" Then
Dic(x) = Dic(x) & "|" & y & "|"
End If
Next Cl
Range("A2:D" & Cells(Rows.Count, "B").End(xlUp).Row).ClearContents
i = 2
For Each Key In Dic
Cells(i, "A") = Split(Dic(Key), "|")(0)
Range(Cells(i, "B"), Cells(i, "C")) = Split(Key, "|")
Cells(i, "D") = Replace(Split(Replace(Dic(Key), "||", ";"), "|")(1), ":", ";")
i = i + 1
Next Key
Set Dic = Nothing
End Sub
The example you are trying to copy seems overly complex and relies on objects only available on the Windows platform. I started from scratch to meet your needs with simpler code--I hope you are able to follow it and adjust as needed.
It combines data in this sheet:
into this:
Sub merge_rows()
Dim last_row As Long
Dim row As Long
Dim s As Worksheet
Dim col As Integer
Set s = ActiveSheet 'use this line to process the active sheet
'set s = thisworkbook.Worksheets("Sheet1") ' use this line to process a specific sheet
last_row = s.Cells(s.Rows.Count, 1).End(xlUp).row 'find the last row with data
For row = last_row To 3 Step -1
If s.Cells(row, "D").Value = s.Cells(row - 1, "D").Value Then
' found a match in column d
' add column G
s.Cells(row - 1, "G").Value = s.Cells(row - 1, "G").Value + s.Cells(row, "G").Value
' add column H
s.Cells(row - 1, "H").Value = s.Cells(row - 1, "H").Value + s.Cells(row, "H").Value
'append all other columns if different
For col = 1 To 6
If Not s.Cells(row, col).Value = s.Cells(row - 1, col).Value Then
s.Cells(row - 1, col).Value = s.Cells(row - 1, col).Value & " " & s.Cells(row, col).Value
End If
Next
' now delete the duplicate row
s.Rows(row).Delete
End If
Next
End Sub

Excel VBA Code to subtract the quantity from another sheet

I have 3 sheets which name are Sheet1, Sheet2 and Sheet3. All sheets have the same columns. I have been using a SUMIFS formula in Sheet2.Range("C2"):
=SUMIFS(Sheet1!$C$2:$C$15,Sheet1!$B$2:$B$15,'Sheet2'!B2,
Sheet1!$A$2:$A$15,'Sheet2'!A2,Sheet1!$D$2:$D$15,"="&'Sheet2'!D2)-
SUMIFS(Sheet3!$C$2:$C$15,Sheet3!$B$2:$B$15,'Sheet2'!B2,
Sheet3!$A$2:$A$15,'Sheet2'!A2,Sheet3!$D$2:$D$15,"="&'Sheet2'!D2)
I have prepared below code which takes the value of Sheet1 Column C by matching Column A, B and D with Sheet2, and paste the result in Sheet2 Column C.
I have been looking for a way to to subtract the Sheet3 Column C quantity from Sheet1 Column C by matching Column A, B and D then its result should be pasted into Sheet2 Column C.
The file and data are attached here:
Dim dict As Object
Dim searchrange As Range
With Sheet1
Dim last_y As Long
Dim i As Long
Set dict = CreateObject("Scripting.Dictionary")
last_y = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 2 To last_y
dict(.Cells(i, 1).Value & .Cells(i, 2).Value & .Cells(i, 4).Value) = _
dict(.Cells(i, 1).Value & .Cells(i, 2).Value & .Cells(i, 4).Value) + _
.Cells(i, 3).Value
Next i
End With
With Sheet3
last_y = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 2 To last_y
.Cells(i, 3).Value = dict(.Cells(i, 1).Value & .Cells(i, 2).Value & _
.Cells(i, 4).Value)
Next i
End With
If all you need is a direct comparison then using a Dictionary is probably not the best method. I would just iterate through all 3 sheets as long as its under 100k rows. You could get fancy with .Find and .FindNext but the easiest is just a good old For Loop.
If I'm understanding your request, you need all values from Sheet 1 to be subtracted by a corresponding value from sheet 3 (if it exists) and then outputted into the matching row of sheet 2 (if it exists). Here's how I would do that:
Sub rowMatch()
Dim a As String, b As String, c As Double, d As String
For i = 2 To Sheet1.Cells(Sheet1.Rows.Count, 1).End(xlUp).Row
'Grab the Sheet1 values
a = Sheet1.Cells(i, 1).Text
b = Sheet1.Cells(i, 2).Text
c = Sheet1.Cells(i, 3).Value
d = Sheet1.Cells(i, 4).Text
'Check Sheet3
For j = 2 To Sheet3.Cells(Sheet3.Rows.Count, 1).End(xlUp).Row
If Sheet3.Cells(j, 1).Text = a _
And Sheet3.Cells(j, 2).Text = b _
And Sheet3.Cells(j, 4).Text = d _
Then
c = c - Sheet3.Cells(j, 3).Value
End If
Next j
'Put into Sheet2
For k = 2 To Sheet2.Cells(Sheet2.Rows.Count, 1).End(xlUp).Row
If Sheet2.Cells(k, 1).Text = a _
And Sheet2.Cells(k, 2).Text = b _
And Sheet2.Cells(k, 4).Text = d _
Then
Sheet2.Cells(k, 3) = c
End If
Next k
Next i
End Sub
Edit: To further improve this, you may want to make the code more flexible by only comparing the strings after doing operations like UCASE() and TRIM(). And you may want to add in exceptions for if a, b, or d are blank. Maybe in those cases you want to allow partial matches. My example was just the basic idea.

Copy and pasting all values from one sheet to another

I have a macro that creates a sheet full of data. I recently added new sheets so that unique values can go into each one. For example if a row contains "Pole Change Out" then that entire row is copy and pasted into the "Pole Change Out" sheet. there are 4 different sheets. My problem is, since some values are determined by a formula in vba, some values are not moving into the new sheet.
Sub copy_paste_based_on_cell_interior_rgb()
Dim LastRow As Long
Dim i As Long, j As Long
'Find the last used row in a Column: column A in this example
With Worksheets("Make-Ready")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'first row number where you need to paste values in Sheet1'
With Worksheets("Pole Change Out")
j = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
End With
For i = 1 To LastRow
With Worksheets("Make-Ready")
If .Cells(i, 27).Value = "Pole Change-Out" Then
.Rows(i).Copy Destination:=Worksheets("Pole Change Out").Range("A" & j)
j = j + 1
ElseIf .Cells(i, 27).Value = "New Midspan Pole" Then
.Rows(i).Copy Destination:=Worksheets("Midspan Poles").Range("A" & j)
j = j + 1
ElseIf .Cells(i, 104).Value = "Yes" Then
.Rows(i).Copy Destination:=Worksheets("Anchor Replacement").Range("A" & j)
j = j + 1
End If
End With
Next i
End Sub
As #scottCraner and the others pointed out. You are trying to use the first empty cell variable from one sheet on the other two sheets. The update to your code will automatically update the first blank cell for each sheet.
Sub copy_paste_based_on_cell_interior_rgb()
Dim LastRow As Long
Dim i As Long ', j As Long
'Find the last used row in a Column: column A in this example
With Worksheets("Make-Ready")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'first row number where you need to paste values in Sheet1'
'With Worksheets("Pole Change Out")
' j = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
'End With
For i = 1 To LastRow
With Worksheets("Make-Ready")
If .Cells(i, 27).Value = "Pole Change-Out" Then
.Rows(i).Copy Destination:=Worksheets("Pole Change Out").Cells(Rows.Count, 1).End(xlUp).Offset(1)
'j = j + 1
ElseIf .Cells(i, 27).Value = "New Midspan Pole" Then
.Rows(i).Copy Destination:=Worksheets("Midspan Poles").Cells(Rows.Count, 1).End(xlUp).Offset(1)
'j = j + 1
ElseIf .Cells(i, 104).Value = "Yes" Then
.Rows(i).Copy Destination:=Worksheets("Anchor Replacement").Cells(Rows.Count, 1).End(xlUp).Offset(1)
'j = j + 1
End If
End With
Next i
End Sub

Copy cell and adjacent cell and insert as new row: Excel VBA

I'm trying to copy a cell and the adjacent cell in a row and insert it as a new row with all the data to the right of this cell also copied over. My data looks like this after mining.
and im trying to get my data to look like this:
the image above is just one record but essentially its moving all the people and their corresponding position in the original row to a new row. In each row there are about 5 employees and their positions.
thanks
EDIT Attempted code for just 2 cols. 1 position. the idea was to create the empty rows and just copy the rest of the data with auto fill, then work from there
Sub TransposeInsertRows()
Dim rng As Range
Dim i As Long, j As Long, k As Long
Dim x As Long, y As Long
Set rng = Application.InputBox _
(Prompt:="Range Selection...", _
Title:="Enter the name col and pos col", Type:=8)
Application.ScreenUpdating = False
x = rng(1, 1).Column + 2
y = rng(1, rng.Columns.Count).Column
For i = rng(rng.Rows.Count, 1).Row To rng(1, 1).Row Step -1
If Cells(i, x) <> "" And Cells(i, x + 1) <> "" Then
k = Cells(i, x - 2).End(xlToRight).Column
If k > y Then k = y
For j = k To x + 1 Step -1
Cells(i + 1, 1).EntireRow.Insert
With Cells(i + 1, x - 2)
.Value = .Offset(-1, 0)
.Offset(0, 1) = .Offset(-1, 1)
.Offset(0, 2) = Cells(i, j)
End With
Cells(i, j).ClearContents
Next j
End If
Next i
Application.ScreenUpdating = True
End Sub
If there are always 5 people in each row then this should do it:
Sub foo()
LastRow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow 'loop through rows
For x = 1 To 10 Step 2 'loop through columns
LastRow2 = Sheet2.Cells(Sheet2.Rows.Count, "A").End(xlUp).Row + 1 'find the next free row on Sheet2
Sheet2.Cells(LastRow2, 1).Value = Sheet1.Cells(i, x).Value 'add Person Name to Sheet2
Sheet2.Cells(LastRow2, 2).Value = Sheet1.Cells(i, x + 1).Value 'add position to Sheet2
Sheet1.Range("K" & i & ":U" & i).Copy Destination:=Sheet2.Cells(LastRow2, 3) 'copy range from K to U to Sheet2
Next x
Next i
End Sub

Microsoft Excel VBA Scripting: Recursive column matching

Sub NewMacro()
Dim endRow As Long
endRow = Sheet1.Range("A999999").End(xlUp).Row
For i = 1 To endRow
If Sheet1.Range("A" & i).Value = Sheet1.Range("F" & i).Value Then
Sheet1.Range("K" & i).Value = "Yes" Else
Sheet1.Range("K" & i).Value = "No"
End If
Next i
End Sub
This will compare column A with column F and displays the result in column K.
What I need is if this value is true, then like the above it should compare column B with column G, column C with column H and so on......and should display the results in next column. Please help.
I think you need a loop on the columns:
Sub NewMacro()
Dim endRow As Long
Dim i As Long
Dim c As Long
With Sheet1
endRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To endRow
For c = 1 To 5
If .Cells(i, c).Value = .Cells(i, c + 5).Value Then
.Cells(i, c + 10).Value = "Yes"
Else
.Cells(i, c + 10).Value = "No"
End If
Next c
Next i
End With
End Sub
This compares column A with F, column B with G, column C with H, column D with I and column E with J. Results are placed in columns K, L, M, N and O respectively.
This is equivalent to using the formula =IF(A1=F1,"Yes","No") in cell K1 and copying it across and down.
And a version which will update columns with "Yes", but stop as soon as it reaches a "No":
Sub NewMacro()
Dim endRow As Long
Dim i As Long
Dim c As Long
With Sheet1
endRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To endRow
For c = 1 To 5
If .Cells(i, c).Value = .Cells(i, c + 5).Value Then
.Cells(i, c + 10).Value = "Yes"
Else
.Cells(i, c + 10).Value = "No"
Exit For
End If
Next c
Next i
End With
End Sub

Resources