Trying to run a macro in Excel to remove non dupes so dupes can be examined easily.
Step through each cell in column "B", starting at B2 (B1 is header)
During run, if current cell B has a match anywhere in column B - leave it, if it' unique - remove entire row
The code below is executing with inconsistent results.
Looking for some insight
Sub RemoveNonDupes()
Selection.Copy
Range("B2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Range("B2:B5000").AdvancedFilter Action:= xlFilterInPlace, CriteriaRange:= Range("B2"), Unique := True
Range("B2:B5000").SpecialCells(xlCellTypeVisible).EntireRow.Delete
ActiveSheet.showalldata
End Sub
Not the most direct route, but you could have the macro insert between B and C. Then dump a formula in that column that counts.
Something like =countifs(B:B,B:B) That will give you a count of how many times a record shows, then you can set the script to Loop deleting any row where that value is 1.
Something like
Sub Duplicates()
Columns("B:B").Insert Shift:=xlToRight ' inserts a column after b
count = Sheet1.Range("B:B").Cells.SpecialCells(xlCellTypeConstants).count ' counts how many records you have
crange = "C1:C" & count ' this defines the range your formula's go in if your data doesn't start in b1, change the c1 above to match the row your data starts
Sheet1.Range(crange).Formula = "=countifs(B:B,B:B)" ' This applies the same forumla to the range
ct=0
ct2=0 'This section will go cell by cell and delete the entire row if the count value is 1
Do While ct2 < Sheet1.Range("C:C").Cells.SpecialCells(xlCellTypeConstants).count
For ct = 0 To Sheet1.Range("C:C").Cells.SpecialCells(xlCellTypeConstants).count
If Sheet1.Range("C1").Offset(ct, 0).Value > 1 Then
Sheet1.Range("C1").Offset(ct, 0).EntireRow.Delete
End If
Next
ct2 = ct2 + 1
Loop
Sheet1.Columns("B:B").EntireColumn.delete
end sub
Code isn't pretty, but it should do the job.
**Updated code per comments
Sub Duplicates()
Columns("C:C").Insert Shift:=xlToRight ' inserts a column after b
count = Activesheet.Range("C:C").Cells.SpecialCells(xlCellTypeConstants).count ' counts how many records you have
crange = "C1:C" & count ' this defines the range your formula's go in if your data doesn't start in b1, change the c1 above to match the row your data starts
Activesheet.Range(crange).Formula = "=countifs(B:B,B:B)" ' This applies the same forumla to the range
ct=0
ct2=0 'This section will go cell by cell and delete the entire row if the count value is 1
'''''
Do While ct2 < Activesheet.Range("C:C").Cells.SpecialCells(xlCellTypeConstants).count
For ct = 0 To Activesheet.Range("C:C").Cells.SpecialCells(xlCellTypeConstants).count
If Activesheet.Range("C1").Offset(ct, 0).Value = 1 Then
Activesheet.Range("C1").Offset(ct, 0).EntireRow.Delete
End If
Next
ct2 = ct2 + 1
Loop
ActiveSheet.Columns("C:C").EntireColumn.delete
end sub
You can try that updated code, the part with the Do Loop is what will delete each column, I fixed it to delete any row where the count is 1.
Based on what I understand, your data should be in column B and the counts should be in column C. If that isn't correct, update the formula's to match
Chris, to examine the unique values in a given range of data, I suggest utilizing Excel's Advanced Copy function in a slightly different way:
Range("RangeWithDupes").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("TargetRange"), unique:=True
The operation will provide you a list of unique values from 'RangeWithDupes' located at 'TargetRange'. You can then use the resultant range to manipulate the source data in many ways. Hope this helps.
Related
This is the scenario:
two worksheets - Sheet1 & Sheet2
Sheet1 has everything Sheet2 has and more
I am looking to find an exact match in Sheet1 Column A and B to data in Sheet2 Columns A and B (row location will always be different than Sheet1) and then copy the contents of column C from sheet 1 to the appropriate row in Sheet2 column C.
I have tried multiple Match statements. I am getting all kinds of errors and cannot even get an incorrect result.
Sheet1 is the primary table. Sheet2 is a subset of data from Sheet1 (the results of a pivot table drill-down. The idea is to look at each row, columns A & B in Sheet2 and find a match in Cols A & B of Sheet1. Then copy the value from the same row in column C to the corresponding row in Sheet2.
This was one attempt:
Sub match_1()
Sheets("Sheet2").Range("A2:B2").Value = WorksheetFunction.Match( _
Sheets("Sheet1").Range("A2").Value, _
Sheets("Sheet1").Range("A:B"), _
0)
End Sub
Sheet1:
Sheet2:
There are three problems with how you are using the Match function:
Match expects a single row or column of data in the second argument. You have passed it 2 columns, so it will always return a #N/A error
Match returns the item number within the Row/Column which matches the first argument. You then need to use Index or Range or Cell to get the value.
Match does not match multiple columns. I explain here how to do this match without VBA
Using my example from Point 3, here is some code to achieve your aim:
Sub matchValues()
Dim calculation As XlCalculation, screenUpdating As Boolean
calculation = Application.calculation: Application.calculation = xlCalculationManual
screenUpdating = Application.screenUpdating: Application.screenUpdating = False
Dim rCaseLink As Range
With Worksheets("Sheet2")
Set rCaseLink = .Range(.Cells(2, 3), .Cells(.Rows.Count, 2).End(xlUp).Offset(0, 1))
End With
With rCaseLink
'This formula will pull back the Value for Column C based on A and B
.Formula = "=INDEX(Sheet1!$C$2:$C$999, AGGREGATE(15, 6, ROW(Sheet1!$A$2:$A$999)/(--(Sheet1!$A$2:$A$999=$A2)*--(Sheet1!$B$2:$B$999=$B2)), 1)-1, 1)"
.Calculate
.Value = .Value 'This will flatten the value, so that it is no longer a formula
End With
'Reset Excel
Application.calculation = calculation
Application.screenUpdating = screenUpdating
End Sub
I have 7 columns representing 7 diferent (let's call it) sources of input.
Row 1 of each column has the names of each source.
Row 2 of each column is a sum of all rows from the 4th down. Ex: A2 = SUM(A4:A1048576)
Since I am suposed to make random entries to each column, I want Row 3 of each column to be standard user input field so that any value input on 3rd row of each column is appended to the first empty cell in that column, triggered by some event (keypress, buttonpress, sheetupdate?). That is, the first entry to column "A" in "A3" will be put in "A4", second entry to "A3" should be put in "A5" and so on. Same goes for each column, independently. Also, if possible, I want cells in Row 3 to be cleared in the end.
How do i do this?
Please, answer with full tutorial explanation or a heavily sourced one, because my experience with EXCEL and VBA is close to none.
For anyone else finding this answer, understand that each column is independent of the others so it doesn't matter if the row counts vary by column.
Paste the following code into the Worksheet you plan to use. This will monitor changes ONLY in row 3 (but all columns - you can alter to only monitor the seven columns you want to watch).
When a change is detected in row 3, the column is determined, then the last used ROW is found for that column. The value entered is moved to the first available row, the value entered on row 3 is erased, and the SUM in row 2 is updated to reflect the new sum range.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ColName As String
Dim lLastRow As Long ' Saves Last Row for any column
Dim lColumn As Long
' This will monitor changes made in row 3 only.
' - move entered value to end of column
' - erase row 3 value entered
' - change 'SUM' in row 2 to reflect new row
On Error GoTo Enable_Events ' Need this! If error, need to enable events!!
If Target.Row <> 3 Then Exit Sub ' Only track row 3 changes
Application.EnableEvents = False ' Turn off event tracking because we make changes
lColumn = Target.column ' Get column that's being used.
With ActiveSheet 'Find the last used row in a Column
lLastRow = .Cells(.Rows.Count, Target.column).End(xlUp).Row
End With
Cells(lLastRow + 1, Target.column).value = Target.value ' Move value to end
Target.value = "" ' Clear value entered
' Get Column name (A, B, C...) then create new SUM
ColName = Left(Cells(1, lColumn).Address(False, False), 1 - (lColumn > 26))
Cells(2, lColumn).Formula = "=SUM(" & ColName & "4:" & ColName & lLastRow + 1 & ")"
Enable_Events:
Application.EnableEvents = True
End Sub
I'm trying to write a macro that will select records in sheet1, column A (1 row per record) and attempt to match to records in sheet2, column A (zero to 40 rows per record).
If a match is found, I want the macro to search from a list of strings (found in sheet3, A1:A75) that may appear in the sheet2 matched rows, column F. If the records match, and one
of the target strings is found, I want the macro to enter "1" for the row being matched in sheet1, column P, 0 if no match is found. And then continue looping through all of the records of sheet1, column A. I haven't included my working code because it would be laughable to you all. Please help. Thank you in advance.
Since you asked a question without providing any code, I'm giving you an answer which is probably going to have to be adapted to what you are trying to do.
My macro looks for value from sheet1 and in sheet2 and returns matched values.
Sub MatchRecord()
Dim i As Integer
Dim j As Integer
i = 1
Do Until Sheets("Sheet1").Cells(i, 1) = "" 'do until empty cell in A column (in first sheet)
CompareValue = Sheets("Sheet1").Cells(i, 1)
j = 1
Do Until Sheets("Sheet2").Cells(j, 1) = "" ' do until empty cell in A column (in second sheet)
If CompareValue = Sheets("Sheet2").Cells(j, 1) Then
FindedValue = Sheets("Sheet2").Cells(j, 2) 'if CompareValue is funded in sheet2 it will return value in next column of matching row
Else
End If
Loop
Sheets("Arkusz2").Cells(i, 2) = FindedValue ' Cell in next column of searching cell will takes value from funded value
FindedValue = "" ' clear this variable
i = i + 1 'next cell to compare
Loop
End Sub
I've imported the results of a broken link search in to Excel and I now need to sort the results based on the error code. I can't get my head around how to do this because the error code is in the row below the URL and not in a column next to it. Also, some URLs take up more than one row.
Here is a screenshot of part of the spreadsheet:
How would I go about grouping all results with error 404 together?
Below you'll find a VBA code that do what you need. As I don't have the original sheet I create an excel and put some random data. Works fine for me.
Sub test()
Dim row, rowDest, rowAux As Integer
Dim source As Worksheet
Dim dest As Worksheet
'Replace here by the name of the worksheet that contains the data
Set source = Worksheets("Sheet1")
'This is the sheet where the modified data will be placed
Set dest = Worksheets("Sheet2")
'Start row (source sheet)
row = 1
'Start row (dest sheet)
rowDest = 1
'This is an auxiliary variable used to fill the error code column
rowAux = 0
'Go to the last line (column 1) of your source sheet and write the string !q
'This will be used as a flag to know where your data finish
While (source.Cells(row, 1).Value <> "!q")
If (InStr(source.Cells(row, 1).Value, "http") > 0) Then
dest.Cells(rowDest, 1).Value = source.Cells(row, 1).Value
If (rowAux = 0) Then rowAux = rowDest
rowDest = rowDest + 1
ElseIf (InStr(source.Cells(row, 1).Value, "error code") > 0) Then
While (dest.Cells(rowAux, 1).Value <> "")
dest.Cells(rowAux, 2).Value = source.Cells(row, 1).Value
rowAux = rowAux + 1
Wend
rowAux = 0
End If
row = row + 1
Wend
End Sub
My dataset and results:
Source sheet:
Dest sheet:
Insert a column to the left of A and fill in with a sequence of numbers (1, 2, 3, ...). Now sort by column B. Select all the error code entries and drag them to column c (or some other empty column). Resort the sheet by the sequence of numbers in column A. Now with everything ordered and the error codes is a separate column (C), you can right-click on C1, and select shift cells up. Column A can be deleted, and you can sort by the URL's (although it looks like you clean up the text a bit).
This is going to be difficult to do unless you can get the error code in the same row as the URL. However, you can still do it by using the SEARCH function on the error code. This will find the 404 error, but it won't give you the URL in the cell beneath it. Therefore, you need a function that checks to see if the cell beneath it's cell has found a 404 code. Then you can filter on the "true" values and get two rows.
Create a new column in A, and use the function below.
=IF(ISNUMBER(SEARCH("404",B1)),1,IF(A2=1,2,0))
Filter down on 1 and 2 values.
Solution based on http://office.microsoft.com/en-us/excel-help/check-if-a-cell-contains-text-HP003056106.aspx and the function:
=IF(ISNUMBER(SEARCH("v",A2)),"OK", "Not OK")
Subject to some constraints (but they are not in your Q!) this formula in an inserted ColumnA may serve:
=INDEX(C1:C3,MATCH("*error code:*",C1:C3,0))
along with =ROW() in an inserted ColumnB (though could be elsewhere) and both copied down at the same time.
The formulae should be converted to values (copy ColumnsA:B, Paste Special..., Values over the top) and sorting be based on ColumnA then ColumnB. The rows blank in ColumnC may be deleted, as also those with error codes in that column.
I have searched the web and tried all possible solutions, but in vain.
There are auditors looking at specific customers in specific areas.
I have three worksheets with data on it: Summary sheet, Raw Data sheet and an Area Listing sheet. The data gets transferred from the data sheet to the summary sheet, but contains areas that do not belong to the specific auditor. The area listings have an indicator Yes/No that must be used to clear the summary sheet of unwanted areas.
I therefore need to delete the unwanted areas from the Summary sheet by first matching the area names on both sheets and then delete those that are marked with a "No" on the area listing sheet.
The core coding I have tried:
If ActiveCell.Formula = "=VLookup(B2,Areas!C2:D,1,False)"=True _
And Sheets("Areas").Range("D2").Value = "No" Then
Sheets("Summary").EntireRow.Delete
Where B2 is the column in Summary containing the Areas and C2 is the corresponding column in Areas with D2 the column in Areas listing the selections of Yes / No.
How do I then write the code to delete the Rows in Summary where the areas are matching in the Summary and the Areas sheet and the indicator in the Areas sheet is "No"?
I have also tried:
For I = LastRowCheck To 1 Step -1
If Sheets("Summary").Range("B" & LastRowCheck).Value = _
Sheets("Areas").Range("C" & sdRow).Value _
And Sheets("Areas").Range("D" & NoRow).Value = "No" Then
If DelRange is Nothing Then
Set DelRange = Sheets("Summary").Rows(i)
End If
If not DelRange Is Nothing Then DelRange.EntireRow.Delete
End If
Next i
Can somebody please tell me where I am missing the boat?
it seems to me, that the areas sheet is going to have.. lets say 50 different areas, and the summary sheet is going to have however many rows, each with an area from the area sheet. so multiple rows would have the same area. so, you want to loop through all the rows on the summary sheet, find the corresponding area from the area sheet, and see if that area has a "no" value in column D.
given the above understanding, the following 2 options should both work:
A)
loop through all rows on areas sheet and load all area names with D
column value of "No" into an array.
loop through all rows on summary sheet
use inner loop to check and see if current row in summary sheet is
found in array of "bad areas"
delete entire row
B)
use a loop to find all rows in the area sheet with a D column value of "No" and load the names from each of these areas into an array.
use said array as the criteria for a data filter, filtering the area name column in the summary sheet
delete all visible rows (ones with areas found on areas sheet with D column value of "No"
A Code:
Dim strArray() as variant
ReDim strArray(1 to 1)
dim deleted as boolean 'keeps track of whether row was delete or not
Sheets("Area Sheet").Activate
Range ("A1").Activate 'where assuming column a has area name
for i = 1 to lastrow
if ActiveCell.offset(0, 3).formulaR1C1 = "No" then 'column D, I have had bad experience with .value so i always use formulaR1C1
strArray(i) = ActiveCell.formulaR1C1
end if
ActiveCell.offset(1,0).activate
next
Sheets("Summary Sheet").activate
Range("A1") ' again, assuing a has area name
for i = 1 to endrow
delete = false 'reset delete before inner loop
for j = 1 to ubound(strArray)
if ActiveCell.formulaR1C1 = strArray(i) then
ActiveCell.entireRow.delete xlShiftUp
deleted = true
exit for 'exits inner loop
else
deleted = false
end if
next
if not deleted then ActiveCell.offset(1,0).offset ' move down to next row if curent row was not deleted
next
B Code:
'use same as A code to get all areas with D Column "No" into array
Dim rng as Range
Range("A1").activate ' after activating summary sheet, again, assuming a has area name
ActiveCell.entireColumn.select
selection.AutoFilter Field:=1, Criteria1:=strArray, Operator:=xlFilterValues ' this will filter so only rows with area and column D of "No" will be visible.
set rng = Range("A1", Cells(lastrow, lastcolumn)).SpecialCells(xlCellTypeVisible) ' this will get all visible cells (ones that are visible with current filter condition)
rng.entirerow.delete xlshiftup 'will delete all rows in rng
depending on the amount of data, A) with application.Screenupdating =false may be faster than filter (use doesnt see whats happening behind the scenes.) do make sure to do Application.screenupdating = true again after to turn that back on.
code may need tweaking for spelling mistakes etc.. but basis should be there
I did not set endrow ever as everyone has their own way of getting the last row.
HTH
good luck!