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.
Related
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
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
I want to create column that will be filled by city names repeated "x" times.
Data taken from another sheet (Sheet1, column A (text), B (text) and F (formula)):
London Q 3
Paris R 2
Want to have (Sheet2, column A (text), B (text) and C (Number)):
London Q 1
London Q 2
London Q 3
Paris R 1
Paris R 2
I know it is quite easy but I'm new in VBA :/
I've found code like below (from description it should do what I want), but - this loop never ends and xls crushes so I'm not able to see if it is doing what I want or not.
Sub RunMe()
Dim CopyX, x As Integer
CopyX = Sheets("Sheet2").Range("F1")
Sheets("Sheet1").Select
Range("A1").Copy
Do
x = x + 1
Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Loop Until x = CopyX
Application.CutCopyMode = False
End Sub
This code
- loops through each item in sheet1
- repeats the city name however many times are specified in col F
- puts a 1 alongside the first entry
- completes the series in successive cells in steps of 1 until the col F value is reached.
You may have to adjust sheet names.
Sub x()
Dim r As Long, ws2 As Worksheet
Set ws2 = Sheets("Sheet2")
With Sheets("Sheet1")
For r = 1 To .Range("A" & Rows.Count).End(xlUp).Row
ws2.Range("A" & Rows.Count).End(xlUp)(2).Resize(.Cells(r, 6).Value).Value = .Cells(r, 1).Resize(, 2).Value
ws2.Range("B" & Rows.Count).End(xlUp)(2).Value = 1
ws2.Range("B" & Rows.Count).End(xlUp).DataSeries Step:=1, Rowcol:=xlColumns, Type:=xlLinear, Stop:=.Cells(r, 6).Value
Next r
End With
End Sub
Everything went great after inserting if statement because in data column F there also appears "0" values. Added also clearing and sorting. Maybe someone will use it so I implement whole code :)
Sub x()
Dim r As Long, ws2 As Worksheet
With Sheets("Sample_size")
Range(.Range("A2"), .Range("D2").End(xlDown)).ClearContents
End With
Set ws2 = Sheets("Sample_size")
With Sheets("Pres")
For r = 2 To .Range("A" & Rows.Count).End(xlUp).Row
If .Cells(r, 5).Value > 0 Then
ws2.Range("B" & Rows.Count).End(xlUp)(2).Resize(.Cells(r, 5).Value).Value = .Cells(r, 1).Resize(, 2).Value
ws2.Range("C" & Rows.Count).End(xlUp)(2).Resize(.Cells(r, 5).Value).Value = .Cells(r, 2).Resize(, 2).Value
ws2.Range("d" & Rows.Count).End(xlUp)(2).Resize(.Cells(r, 5).Value).Value = .Cells(r, 5).Resize(, 2).Value
ws2.Range("A" & Rows.Count).End(xlUp)(2).Value = 1
ws2.Range("A" & Rows.Count).End(xlUp).DataSeries Step:=1, Rowcol:=xlColumns, Type:=xlLinear, Stop:=.Cells(r, 5).Value
End If
Next r
End With
ws2.Range("A2:D2").End(xlDown).Sort _
Key1:=Range("D2"), Order1:=xlDescending, _
key2:=Range("c2"), order2:=xlAscending, _
key3:=Range("b2"), order3:=xlAscending
End Sub
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
I have a cell (U4, for example) where I insert a value. I'll call it A, for example.
I want to copy all the values in Column K higher than A (starting in row 4), and place them in Column N (starting in row 4 also). Besides that, i want to copy the correspondent values in Column L and place them in column O.
Right now I have this, just for Column K:
A = Range("U4").Value
Cotacopy = 4
With Range("K4")
If .Cells(1, 1).Value > A Then
Range(.Cells(1, 1), .End(xlDown)).Copy Destination:=Sheets("Cálculo").Range("N" & Cotacopy)
x = x + 1
Else
End If
End With
I don't know if this is entirely correct, i'm adapting another process where i copy all the cells in one column that have value.
How about the following For loop:
Sub CopyHigherValue()
Dim lastrow As Long
lastrow = Cells(Rows.Count, "A").End(xlUp).Row
y = 4
For x = 4 To lastrow
If Cells(x, 1).Value < Cells(x, 11).Value Then
Cells(y, 14).Value = Cells(x, 11).Value
Cells(y, 15).Value = Cells(x, 12).Value
y = y + 1
End If
Next x
End Sub