VBA Check duplicates (column) and copy cells from one row to another that is duplicate - excel

Excel 2007 [VB]
In my macro I filter by color to find duplicated values (on column "J" I have Highlight Cells Rules - Duplicates). Duplicated records in column "J" are named in column "K" as "Copy" or "Original".I would like to find "Copy" for each "Original" record which is always under (but not 1 but more rows) and copy cells value from column N:R of "Copy" row to row with "Original".
I hope I wrote it clearly but if not screenshot under.
Table
Begining of my macro:
Sub copy_original()
Dim lastRow As Long
Dim wb2 As Excel.Workbook
Application.DisplayAlerts = False
Application.AlertBeforeOverwriting = False
Application.ScreenUpdating = True
Set wb2 = ThisWorkbook
wb2.Sheets("Sheet1").AutoFilterMode = False
wb2.Sheets("Sheet1").Range("A4:U4").AutoFilter Field:=10, Criteria1:=RGB(255, 204, 0), Operator:=xlFilterCellColor
lastRow = wb2.Sheets("Sheet1").Cells(Rows.Count, "C").End(xlUp).Row
For x = lastRow To 5 Step -1
If...
...
wb2.Sheets("Sheet1").AutoFilterMode = False
End Sub
I looked for something similiar that can help and I found such a scripts:
Check if one cell contains the EXACT same data as another cell VBA
Find cells with same value within one column and return values from separate column of same row
Excel: Check if Cell value exists in Column, and return a value in the same row but different column
But to be honest I can't figure it out how to connect it into one working macro.
I would be gratefull for help.

Try this:
Sub copy_original()
Dim filteredRng As Range, cl As Range, rw As Integer
Application.DisplayAlerts = False
Application.AlertBeforeOverwriting = False
Application.ScreenUpdating = True
With ThisWorkbook.Worksheets("Sheet1")
.AutoFilterMode = False
.Range("A4:U4").AutoFilter Field:=10, Criteria1:=vbRed, Operator:=xlFilterCellColor
Set filteredRng = .Range("J5:J" & .Cells(Rows.Count, "J").End(xlUp).Row)
For Each cl In filteredRng.SpecialCells(xlCellTypeVisible)
If cl.Offset(0, 1) = "Original" Then
Range("L" & rw & ":R" & rw).Copy Destination:=cl.Offset(0, 2)
End If
rw = cl.Row
Next cl
.AutoFilterMode = False
End With
End Sub

You can try that;
For x = 5 to lastRow
If Cells(x,11) = "Copy" Then
For y = x+1 to LastRow
If Cells(y,10).Value = Cells(x,10) then
Cells(y,14) = Cells(x,14)
Cells(y,15) = Cells(x,15)
Cells(y,16) = Cells(x,16)
Cells(y,17) = Cells(x,17)
Cells(y,18) = Cells(x,18)
End If
Next y
End If
Next x

Related

Deleting Specific Cells In Last Row

After importing the last row of data from a .csv, I am looking to delete specific cells within that data. I know which columns the data will be in but the row will change as I import new data from the latest .csv file. How can I "loop" through the last row (variable) and delete the cells that are less than 1. Again, I do know the column ahead of time but that info may not be necessary. Any help is greatly appreciated.
Sub ImportCSV()
Dim Ws As Worksheet, FileName As String, Last_Row As Long
Application.ScreenUpdating = False
Set Cell = ActiveCell
Set Ws = ActiveWorkbook.Sheets("Raw Data")
FileName = Application.GetOpenFilename("Text Files (*.csv),*.csv")
Set wb = Workbooks.Open(FileName, , True)
Last_Row = ActiveSheet.Range("A:Z").Find("*", , xlValues, , xlByRows, xlPrevious).Row
Cell.Resize(1, 48).Value = Range("A" & Last_Row).Resize(1, 48).Value
wb.Close False
Sheets("Calcs").Range("A" & Rows.Count).End(xlUp).EntireRow.Resize(2).FillDown
End Sub
-Noob
To dynamically find the last row number, you can use the "UsedRange" object. Here is a VBA proc that may help. You would replace "ImportSheetNameHere" with your sheetname. It loops thru only the last row, and only checks the 1st and 2nd columns, but you could change it as needed:
Public Sub DeleteLessThan1()
Dim s, rng, LastRow, Cell
s = "ImportedSheetNameHere"
Set rng = ThisWorkbook.Worksheets(s).UsedRange
LastRow = rng.Rows.Count
'Do 1st column
Set Cell = rng.Cells(LastRow, 1)
If Cell.Value < 1 Then
Cell.Value = ""
End If
'Do 2nd column
Set Cell = rng.Cells(LastRow, 2)
If Cell.Value < 1 Then
Cell.Value = ""
End If
'...Do rest of the columns...
End Sub

Streamlining deleting rows containing dates within a range specified by another cell

I delete rows based on the date in a column.
The dataset is around 85,000 rows and the macro can take from 30s to 5m+ with constant freezing.
I'm not sure if this is due to poorly written code or the size of the dataset.
Sub DeleteCurrentPeriod()
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ThisWorkbook.Worksheets("Transaction list by date")
ws.Activate
On Error Resume Next
ws.ShowAllData
On Error GoTo 0
'Insert column, autofill formula for range
Sheets("Transaction list by date").Select
Columns("AR:AR").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("AR2").Select
ActiveCell.FormulaR1C1 = "=IFERROR(IF(RC[-1]>CONTROL!R20C7,""Y"",""""),"""")"
Selection.AutoFill Destination:=Range("AR2:AR100000"), Type:=xlFillDefault
'Filter on new column for cells matching criteria
ws.Range("$A$1:$BE$100000").AutoFilter Field:=44, Criteria1:="Y"
'Delete rows with matching criteria
On Error Resume Next
Application.DisplayAlerts = False
ws.Range("$A$2:$BE$100000").SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
On Error GoTo 0
'Delete added column and remove filter
Columns("AR:AR").Select
Selection.Delete Shift:=xlToLeft
On Error Resume Next
ws.ShowAllData
On Error GoTo 0
Application.ScreenUpdating = True
Application.Goto Reference:=Range("A1")
End Sub
You can give this a try (use F8 key to run it step by step)
Some suggestions:
Name your procedure and variables to something meaningful
Indent your code (you may use Rubberduckvba.com)
Split the logic in steps
Read about avoiding select and activate here
Code:
Public Sub DeleteCurrentPeriod()
On Error GoTo CleanFail
' Turn off stuff
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim transactionSheet As Worksheet
Set transactionSheet = ThisWorkbook.Worksheets("Transaction list by date")
' Turn off autofilter and show all data
transactionSheet.AutoFilterMode = False
' Find last row
Dim lastRow As Long
lastRow = transactionSheet.Cells(transactionSheet.Rows.Count, "AQ").End(xlUp).Row
' Define range to be filtered
Dim targetRange As Range
Set targetRange = transactionSheet.Range("A1:BE" & lastRow)
' Insert column
transactionSheet.Columns("AR:AR").Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
' Add formula & calculate
transactionSheet.Range("AR2:AR" & lastRow).FormulaR1C1 = "=IFERROR(IF(RC[-1]>CONTROL!R20C7,""Y"",""""),"""")"
Application.Calculate
'Filter on new column for cells matching criteria
transactionSheet.Range("A1:BE" & lastRow).AutoFilter Field:=44, Criteria1:="Y"
'Delete rows with matching criteria
transactionSheet.Range("A2:BE" & lastRow).SpecialCells(xlCellTypeVisible).EntireRow.Delete
'Delete added column and remove filter
transactionSheet.Columns("AR:AR").Delete Shift:=xlToLeft
' Remove filter
transactionSheet.AutoFilterMode = False
'Select A1
Range("A1").Select
CleanExit:
' Turn on stuff again
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Exit Sub
CleanFail:
MsgBox "An error occurred:" & Err.Description
GoTo CleanExit
End Sub
Let me know if it works
I've just made a couple of changes to how you work out the last row and how you do the calculation, it looks like you were comparing to a constant on the Control sheet. I wonder though why are you adding a column in and then deleting it, could you not just perform the calcs in column +1 after your data? Then you wouldn't have to create and delete the column.
'Insert column, autofill formula for range
Dim x as Long, y, lastrow
Sheets("Transaction list by date").Select
'Find the last row used
With Sheets("Transaction list by date")
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
End With
Columns("AR:AR").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("AR2").Select
' Get the constant and perform the comparison, add "Y" to TRUE cells
x= Worksheets("Control").Cells(20,7).value
For y = 1 to lastrow
If Worksheets("Transaction list by date").Cells(y,44)>x then _
Worksheets("Transaction list by date").Cells(y,44).value = "Y"
Next y
'Filter on new column for cells matching criteria
ws.Range("$A$1:$BE$" & lastrow ).AutoFilter Field:=44, Criteria1:="Y"
'Delete rows with matching criteria
On Error Resume Next
Application.DisplayAlerts = False
ws.Range("$A$2:$BE$" & lastrow).SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
On Error GoTo 0
'Delete added column and remove filter
Columns("AR:AR").Select
Selection.Delete Shift:=xlToLeft
On Error Resume Next
ws.ShowAllData
On Error GoTo 0
Application.ScreenUpdating = True
Application.Goto Reference:=Range("A1")
End Sub
Sub RemoveDups()
Const COMPARE_COL As Long = 1
Dim a, aNew(), nr As Long, nc As Long
Dim r As Long, c As Long, rNew As Long
Dim v As String, tmp
a = Worksheets("Sheet1").UsedRange
nr = UBound(a, 1)
nc = UBound(a, 2)
ReDim aNew(1 To nr, 1 To nc)
rNew = 0
v = Date
For r = 1 To nr
tmp = a(r, COMPARE_COL)
If tmp <> v Then
rNew = rNew + 1
For c = 1 To nc
aNew(rNew, c) = a(r, c)
Next c
v = tmp
End If
Next r
Worksheets("Sheet1").UsedRange = aNew
End Sub
This is an answer written by Tim Williams I just set the range to used range and set v to Date, so if you copy and paste this it will search based on the current date you run the macro looking through column 1 (A) If you want to use a different date you'll have to redefine v, you can make that equal to the cell on your control sheet. Took 1 second to "delete" 85000 rows.

Getting error in condition formatting using VBA

I am working on a project in which I am comparing column D with column C of sheet("Backend") and the difference is shown in column E (in %). I'd like to highlight the % difference (column E) in RED color, where the difference is less than -10.00% and greater than 10.00%. Then would like to copy those items from column B corresponding each highlighted cell and paste it in sheet("UPDATER") beneath cell A7.
Attached is the screenshot for your reference
Sub check_date()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wsData As Worksheet, Datasht As Worksheet, lRow As Integer
Set wsData = Sheets("UPDATER")
Set Datasht = Sheets("Backend")
lRow = Datasht.Cells(Rows.Count, 13).End(xlUp).Row
wsData.Range("M8:M" & lRow).Interior.ColorIndex = xlNone
wsData.Range("M8:M" & lRow).FormatConditions.Add Type:=xlExpression, Formula1:="=AND(M8>=EOMONTH(TODAY(),-2)+1,M8<EOMONTH(TODAY(),-1))"
wsData.Range("M8:M" & lRow).FormatConditions(wsData.Range("M8:M" & lRow).FormatConditions.Count).SetFirstPriority
With wsData.Range("M8:M" & lRow).FormatConditions(1).Interior
.Color = RGB(255, 255, 0)
.TintAndShade = 0
End With
wsData.Range("M8:M" & lRow).FormatConditions(1).StopIfTrue = False
Range("M8").Select
End Sub
Here's what I got. It's a bit of a drastic change but I'm hoping this is actually what you're going for.
Sub formatcondition()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wsData As Worksheet, Datasht As Worksheet, lRow As Integer, My_Range As Range, i As Integer, iRow As Integer, cell As Variant, RowNum As Long, lRowUpdater As Long
Set wsData = Sheets("UPDATER")
Set Datasht = Sheets("Backend")
lRow = Datasht.Cells(Rows.Count, 5).End(xlUp).Row
lRowUpdater = wsData.Cells(Rows.Count, 1).End(xlUp).Row
RowNum = 8 'setting the first row in the UPDATER sheet
Datasht.Range("E1:E" & lRow).Interior.ColorIndex = xlNone 'Reset the color before running
wsData.Range("A8:D" & lRowUpdater + 8).ClearContents 'clear your updater sheet. Remove if not needed.
For i = 1 To lRow
On Error GoTo Continue
If Datasht.Range("E" & i).Value < -0.1 Or Datasht.Range("E" & i).Value > 0.1 Then 'If greater than or less than
Datasht.Range("E" & i).Interior.ColorIndex = 6 'Change the color of affected cells if you need that
wsData.Range(wsData.Cells(RowNum, 1), wsData.Cells(RowNum, 4)).Value = _
Datasht.Range(Datasht.Cells(i, 2), Datasht.Cells(i, 5)).Value 'straight copy the values from the cells as it loops rather than using copy/paste
wsData.Range(wsData.Cells(RowNum, 2), wsData.Cells(RowNum, 4)).NumberFormat = "0.00%" 'change the number format of outputted cells to percentages (if needed)
RowNum = RowNum + 1 'move to the next row in the output
End If
Continue:
Resume Nexti
Nexti:
Next i
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
EDIT:
For the date to add a year my version would be just adding to what I gave earlier. Instead we now add an AND function to contain the OR, then checking if the YEAR in the cell is the current year. If you're only wanting this year then we can also forgo the IF statement which was checking that if the current month was January it would incorporate December. But if thats not needed then:
=AND(OR(MONTH(NOW())=MONTH(M8),MONTH(NOW())-1=MONTH(M8)),YEAR(M8)=YEAR(NOW()))
Or
=AND(MONTH(M8)>=MONTH(NOW())-1,MONTH(M8)<MONTH(NOW())+1,YEAR(M8)=YEAR(NOW()))
Both the same length and do the same thing just in different way.

Choose the starting cell of a do-loop

I want to start a loop mid column (Row 15 let's say).
Current code (part of a much larger script)
Range("C2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R15C3"
Dim BlankFound As Boolean
Dim x As Long
'Loop until a blank cell is found in Column C
Do While BlankFound = False
x = x + 1
If Cells(x, "C").Value = "" Then
BlankFound = True
End If
Loop
I tried changing the column ref (C) to a cell (C15). I tried to specify the start and end point (C15:C).
We have a client order form that when they click a button converts to another format ready to be uploaded. The client will fill out various fields that populate rows 1 and 2 (name, address, etc.), then from row three it is the number of orders, i.e.
row
3 part number quantity availability
4 part number quantity availability
I want it to look at the original form and only populate down if it finds a value in the original form's cell.
Then at the end I have another row to add, so I need to be able to say when this loop finishes, add these values (these are just an extra row of totals and some formatting).
The full code-
Sub ButtonMacroLatest()
'Hide alerts
Application.DisplayAlerts = False
'
' Macro8 Macro
'
'Save to users device
ChDir "U:\WINDOWS"
ActiveWorkbook.SaveAs Filename:="U:\WINDOWS\OrderForm.xlsx", FileFormat:= _
xlOpenXMLWorkbook, CreateBackup:=False
'Create new workbook and populate
Workbooks.Add
ActiveCell.FormulaR1C1 = "MSG"
Range("B1").FormulaR1C1 = "=[OrderForm.xlsx]Order!R[1]C"
Range("C1").FormulaR1C1 = "=[OrderForm.xlsx]Order!R[1]C[3]"
Range("D1").FormulaR1C1 = "1400008000"
Range("E1").FormulaR1C1 = "501346009175"
Range("F1").FormulaR1C1 = "=TODAY()"
Range("G1").FormulaR1C1 = "=Now()"
Selection.NumberFormat = "[$-x-systime]h:mm:ss AM/PM"
Range("A2").FormulaR1C1 = "HDR"
Range("B2").FormulaR1C1 = "C"
Range("C2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R4C2"
Range("G2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R[1]C[3]"
Range("H2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R2C4"
Range("K2").FormulaR1C1 = "STD"
Range("L2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R5C2"
Range("N2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R7C2"
Range("O2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R8C2"
Range("Q2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R9C2"
Range("R2").FormulaR1C1 = "=[OrderForm.xlsx]Order!R12C2"
Range("A3").FormulaR1C1 = "POS"
Range("B3").FormulaR1C1 = "=Row()*10-20"
Range("C3").FormulaR1C1 = "=[OrderForm.xlsx]Order!R15C3"
Dim BlankFound As Boolean
Dim x As Long
'Loop until a blank cell is found in Column C
Do While BlankFound = False
x = 14
x = x + 1
If Cells(x, "C").Value = "" Then
BlankFound = True
End If
Loop
Range("D3").FormulaR1C1 = "=[OrderForm.xlsx]Order!R15C1"
Range("E3").FormulaR1C1 = "=[OrderForm.xlsx]Order!R15C2"
Range("F3").FormulaR1C1 = "=[OrderForm.xlsx]Order!R15C5"
Range("G3").FormulaR1C1 = "=[OrderForm.xlsx]Order!R15C7"
'Preformat cells to remove 0 value
Range("A1:AP1000").Select
Range("AP1000").Activate
Selection.NumberFormat = "#;#;"
Range("H3").FormulaR1C1 = "GBP"
Range("L3").FormulaR1C1 = "TRA"
Range("M3").FormulaR1C1 = "=COUNTIF(C[-3], ""POS"")+COUNTIF(C[-3], ""HDR"")"
'Reinstate alerts
Application.DisplayAlerts = True
End Sub
In the client facing form A15:C15 are material/part numbers. If populated those rows should fill down in the new form until there is no entry in the original form.
Customer form
I haven't been able to figure out exactly where you're grabbing values from and where you're putting them, but hopefully this bit of code will give you enough ideas to get yours sorted.
Public Sub ButtomMacroLatest()
Dim wrkBk As Workbook
Dim wbOF As Workbook
Dim shtCSV As Worksheet
Dim shtOF As Worksheet
Dim lLastRow As Long
Dim x As Long, y As Long
'OrderForm is closed so needs opening:
'Set wbOF = Workbooks.Open("U:\.......\OrderForm.xlsx")
'OrderForm is the workbook containing this code:
Set wbOF = ThisWorkbook
'Set a reference to the "Order" sheet and
'find the last row - based on column A being populated.
Set shtOF = wbOF.Worksheets("Order")
lLastRow = shtOF.Cells(Rows.Count, 1).End(xlUp).Row
'Create workbook with 1 sheet and set reference to that sheet.
Set wrkBk = Workbooks.Add(xlWBATWorksheet)
Set shtCSV = wrkBk.Worksheets(1)
'Add headings to the sheet.
shtCSV.Range("A1:G1") = Array("MSG", "SomeHeading", "SomeOtherHeading", "1400008000", _
"501346009175", Date, Now)
'Copy values in cell "A15:J<LastRow>" to "A2" on the new sheet.
With shtOF
'Straight copy
'.Range(.Cells(15, 1), .Cells(lLastRow, 10)).Copy _
Destination:=shtCSV.Range("A2")
'Paste Special
.Range(.Cells(15, 1), .Cells(lLastRow, 10)).Copy
With shtCSV.Range("A2")
.PasteSpecial xlPasteValuesAndNumberFormats
.PasteSpecial xlPasteFormats
End With
'Make the value of one cell equal the value of another cell
'in a loop from row 15 to LastRow and column 1 to 10.
'For x = 15 To lLastRow
' For y = 1 To 10
' shtCSV.Cells(x - 13, y) = .Cells(x, y)
' Next y
'Next x
End With
wrkBk.SaveAs Environ("temp") & "/CSV File.csv", FileFormat:=xlCSV, CreateBackup:=False
End Sub
This took something a lot simpler, it works a treat for what I need. Code:
'Fills column to last row of data from Cell C15
Dim LastRow As Long
LastRow = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Range("C15:C" & LastRow).FillDown
Range("D15:D" & LastRow).FillDown
Range("E15:E" & LastRow).FillDown
Thanks for all of the responses.

Trying to delete all Rows until Cell (A,1) has certain value

Having issues in VBA
Trying to delete all rows until value in row 1 = "**GRAD*"
I get Runtime Error 438
Code Below
Public Sub Delete()
Dim i As Long
i = 1 'Start from row 1
Application.ScreenUpdating = False
With ThisWorkbook.Worksheets("Sheet1")
Do Until .Range("A" & i).Value = "**GRAD"
If .Rage("A" & i).Value <> "**GRAD" Then
.Rows(i).EntireRow.Delete
Else: i = i + 1 'Only increment if the row hasn't been deleted to prevent skipping rows
End If
Loop
End With
Application.ScreenUpdating = True
End Sub
Some help would be appreciated, new to VBA.
L.Dutch already gave you the answer to your question
here's an alternative and faster approach
to delete all rows until value in column 1 = "**GRAD*"
Option Explicit
Public Sub Delete()
Dim lastRowToDelete As Long
Dim f As Range
With ThisWorkbook.Worksheets("Sheet0001") '<-- reference your worksheet
With Range("A1", .Cells(.Rows.Count, 1).End(xlUp)) '<-- reference its columns "A" cells from row 1 sown to last not empty one
Set f = .Find(what:="**GRAD", LookIn:=xlValues, lookat:=xlWhole, after:=.Range("A" & .Rows.Count)) '<-- look for the first cell whose value is "**GRAD"
If f Is Nothing Then '<-- if not found then...
lastRowToDelete = .Rows(.Rows.Count).Row '<-- the last row to delete is the last row of the range
Else '<-- otherwise...
lastRowToDelete = f.Row - 1 '<-- the last row to delete is the one preceeding the one with the found cell
End If
End With
If lastRowToDelete > 0 Then .Range("A1:A" & lastRowToDelete).EntireRow.Delete 'delete all rows in a single shot
End With
End Sub
Typo? I read If .Rage("A" & i).Value <> "**GRAD" Then while it should be If .Range("A" & i).Value <> "**GRAD" Then

Resources