So what I want to do is have a macro in Workbook A that opens Workbook B and C. After that it goes through column A of Workbooks B and C and where the two values are equal it takes the value from workbook C and pastes it into column A of workbook A.
I have written the below code, however it you think it's easier to do it another way please feel free to write your own one. Thank you and please help me :)
Sub ReportCompareAlta()
'
' ReportCompareAlta Macro
' Adds instances where column D is "ALTA"
Dim varSheetA As Variant
Dim varSheetB As Variant
Dim varSheetC As Variant
Dim StrValue As Variant
Dim strRangeToCheck As String
Dim iRow As Long
Dim iCol As Long
Dim WbkA As Workbook
Dim WbkB As Workbook
Dim WbkC As Workbook
Dim counter As Long
Set WbkA = Workbooks.Open(Filename:="G:\Reporting\AH_MISSE_FEB2013.xls")
Set WbkB = Workbooks.Open(Filename:="G:\Reporting\AH_MISSE_MAR2013.xls")
Set WbkC = Workbooks.Open(Filename:="G:\Reporting\ReportCompare.xls")
Set varSheetA = WbkA.Worksheets("LocalesMallContratos")
Set varSheetB = WbkB.Worksheets("LocalesMallContratos")
Set varSheetC = WbkC.Worksheets("Sheet1")
strRangeToCheck = "A1:IV65536"
Debug.Print Now
varSheetA = WbkC.Worksheets("Sheet2").Range(strRangeToCheck) 'may be confusing code here
varSheetB = WbkC.Worksheets("Sheet3").Range(strRangeToCheck) 'may be confusing code here
Debug.Print Now
counter = 0
For iRow = LBound(varSheetA, 1) To UBound(varSheetA, 1)
If varSheetB(iRow, "B") = varSheetA(iRow, "B") & varSheetB(iRow, "B") <> "GERENCIA" & varSheetB(iRow, "B").Value <> "" & varSheetB(iRow, "D") = "ALTA" Then
StrValue = ""
varSheetB.Range("iRow:B").Select
Selection = StrValue
ActiveSheet = varSheetC
Range("A1").Select
Selection.Offset(counter, 0).Value = StrValue
counter = counter - 1
Else
MsgBox ("Done")
End If
Next iRow
End Sub
You need to use the word 'AND' instead of the '&' symbol in your code. Using '&' just concatenates the values, which will cause your if statement to fail.
I see some obvious errors as Mat Richardson points out, using the & is not equivalent shorthand for the AND operator, it's a concatenator, which is not likely what you want when you say:
If varSheetB(iRow, "B") = varSheetA(iRow, "B") & varSheetB(iRow, "B") <> "GERENCIA" & varSheetB(iRow, "B").Value <> "" & varSheetB(iRow, "D") = "ALTA" Then
Which brings me to another error:
varSheetB (and A, and C for that matter) are Variant/Array variables. You cannot index these by iRow, "B" because you cannot use a non-numeric index. Perhaps you mean (iRow, 2).
On a related note: varSheetB.Range("iRow:B").Select this will also fail, because you cannot .Select a Variant. This is not a Range variable. Further, iRow:B is not correct for either of a Variant array or a Range variable. Also, at this point, varSheetB is no longer a Worksheet object variable.
Which brings me to probably the biggest error: You are using the variables varSheetA, varSheetB, and varSheetC to represent (at different times in this code) both a Worksheet Object and a Variant array of values. This is confusing, and probably causing you the errors described above. A variable cannot be both of these things at the same time, so you need to be treating your variants like variants when they are variants, and like worksheets when they are worksheets, or better yet: use worksheet variables for worksheets and variants for arrays, don't use the same variable for multiple purposes.
Sub ReportCompareAlta()
'
' ReportCompareAlta Macro
Dim varSheetA As Worksheet
Dim varSheetB As Worksheet
Dim varSheetC As Worksheet
Dim RangeToCheck As Range
Dim cl as Range
Dim iRow As Long
Dim iCol As Long
Dim WbkA As Workbook
Dim WbkB As Workbook
Dim WbkC As Workbook
Dim counter As Long
Set WbkA = Workbooks.Open(Filename:="G:\Reporting\AH_MISSE_FEB2013.xls")
Set WbkB = Workbooks.Open(Filename:="G:\Reporting\AH_MISSE_MAR2013.xls")
Set WbkC = Workbooks.Open(Filename:="G:\Reporting\ReportCompare.xls")
Set varSheetA = WbkA.Worksheets("LocalesMallContratos")
Set varSheetB = WbkB.Worksheets("LocalesMallContratos")
Set varSheetC = WbkC.Worksheets("Sheet1")
Set RangeToCheck = varSheetA.Range("A1:A65536") '## I change this because you only indicate you want to compare column A ##'
counter = 0
'## just loop over the cells in the range. ##'
'## This is not the most efficient, but it is the easiest ##'
For each cl in RangeToCheck
'## Do your comparison here, e.g: ##'
'## Ignore cells where .Offset(0,3).Value = "ALTA" Or cl.Value = "" ##'
If not cl.Offset(0,3).Value = "ALTA" Or Not cl.Value = vbNullString Then
If Not cl.Value = varSheetB.Range(cl.Address).Value Then
'## The values are not equal, so do something:
varSheetC.Range(cl.Address) = "not equal"
counter = counter+1
Else:
'## The values are equal, so do something else:
varSheetC.Range(cl.Address) = "equal"
End If
End If
Next
MsgBox "Done! There were " & counter & " mismatch values", vbInformation
End Sub
Related
I'm totally new on StackOverflow and on coding itself, I have only so little knowledge so don't be hard on me :)
What is going on:
I have a document stored at C:\Program\Program.xlsm called Program.xlsm
It has different sheets, one of them is Objects - it retreives objects from another file stored at C:\Program\Objects.xlsx.
The Program.xlsm also has a sheet called "Calculate", which has a cell C6 with list data validation and an autocomplete function, yet other values, not the ones in list are also possible.
What I want to do is:
If the Sheet("Calculate").Range("C6").Text is not already at the Objects.xlsx, I want it to be added by a click of a button. I added the button, and added a VBA code:
Sub CommandButton1_Click()
Dim c As Range
Dim dupFound As Boolean
Dim lastRow As Long
Dim wbk1 As Workbook
Dim str As String
Set str = ActiveSheet.Range("C6").Text
Set wbk1 = Workbooks.Open("C:\Program\Objects.xlsx")
dupFound = False
lastRow = wbk1.Worksheets("Objects").Cells(Rows.Count, "B").End(xlUp).Row
For Each c In wbk1.Worksheets("Objects").Range("$B$2:$B$" & lastRow)
Debug.Print c.Value
If c.Value = str Then
dupFound = True
MsgBox "The object already exists"
Exit For
End If
Next c
If dupFound = False Then
Cells(lastRow + 1, "B").Value = str
End If
End Sub
Just a reminder: I am a total newbie at coding, so don't be hard on me :) Thanks!
The main issue here is that in this line
Cells(lastRow + 1, "B").Value = str
you didn't specify in which workbook and worksheet the cell is. Always specify a worksheet, otherwise Excel guesses the worksheet and Excel might guess something else than you.
The second issue is that a string Dim str As String is not an object and therefore needs no Set in Set str = ActiveSheet.Range("C6").Text
Also I recommend to use the WorksheetFunction.Match Method to check if a value is already in column B. This should be much faster then looping through every cell.
Option Explicit
Public Sub CommandButton1_Click()
Dim str As String
str = ActiveSheet.Range("C6").Text
Dim wbk1 As Workbook
Set wbk1 = Workbooks.Open("C:\Program\Objects.xlsx")
Dim lastRow As Long
lastRow = wbk1.Worksheets("Objects").Cells(Rows.Count, "B").End(xlUp).Row
Dim FoundRow As Long
FoundRow = 0 'initialize
'try to match the string with worksheets Objects column B
On Error Resume Next
FoundRow = Application.WorksheetFunction.Match(str, wbk1.Worksheets("Objects").Range("B:B"), 0)
On Error GoTo 0
If FoundRow = 0 Then 'if nothing matched FoundRow is still 0 otherwise FoundRow contains the row number of the match
wbk1.Worksheets("Objects").Cells(lastRow + 1, "B").Value = str
Else
MsgBox "The object already exists in row " & FoundRow
End If
End Sub
I have a spreadsheet with values starting at A5 and running across to column AI, there could be any number of entries to the rows.
Row A contains an Item code (e.g. 000-0000)
I am looking to produce some code to complete the following two actions:
If column AI = yes, then copy entire row and paste below. With every copy add a sequential alphabetised letter to the code in column A (e.g. 000-0000a)
Any help would be greatly appreciated. Everything i've found expands to copying to another sheet and i'm struggling to break down the code.
Thanks
Edit:
Please see below current code I have been trying to get to work which works up to the point of copying the row however fails to paste it.
Sub NewItems(c As Range)
Dim objWorksheet As Worksheet
Dim rngNewItems As Range
Dim rngCell As Range
Dim strPasteToSheet As String
'Used for the new worksheet we are pasting into
Dim objNewSheet As Worksheet
Dim rngNextAvailbleRow As Range
'Define the worksheet with our data
Set objWorksheet = ThisWorkbook.Sheets("Sheet1")
'Dynamically define the range to the last cell.
'This doesn't include and error handling e.g. null cells
'If we are not starting in A1, then change as appropriate
Set rngNewItems = objWorksheet.Range("A5:A" & objWorksheet.Cells(Rows.Count, "A").End(xlUp).Row)
'Now loop through all the cells in the range
For Each rngCell In rngNewItems.Cells
objWorksheet.Select
If rngCell.Value <> "Yes" Then
'select the entire row
rngCell.EntireRow.Select
'copy the selection
Selection.Copy
'Now identify and select the new sheet to paste into
Set objNewSheet = ThisWorkbook.Sheets("Sheet1" & rngCell.Value)
objNewSheet.Select
'Looking at your initial question, I believe you are trying to find the next available row
Set rngNextAvailbleRow = objNewSheet.Range("A1:A" & objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row)
Range("A" & rngNextAvailbleRow.Rows.Count + 1).Select
ActiveSheet.Paste
End If
Next rngCell
objWorksheet.Select
objWorksheet.Cells(1, 1).Select
'Can do some basic error handing here
'kill all objects
If IsObject(objWorksheet) Then Set objWorksheet = Nothing
If IsObject(rngBurnDown) Then Set rngNewItems = Nothing
If IsObject(rngCell) Then Set rngCell = Nothing
If IsObject(objNewSheet) Then Set objNewSheet = Nothing
If IsObject(rngNextAvailbleRow) Then Set rngNextAvailbleRow = Nothing
End Sub
So there are lots of things to address with your code. Many of which I have touched on. But the main thing to observe is that you are testing Column A not Column AI for the presence of "Yes" - so there may not be a match hence no copy.
As the paste destination is determined by a concatenation to create a sheet name you should have a test to ensure that sheet exists.
For testing I simply ensured a sheet called Sheet1a existed, that Sheet1 cell A5 had "a" in it, and there was a "Yes" in column AI. This could be improved but is enough to get you going.
This line is looping column A:
Set rngNewItems = objWorksheet.Range("A5:A" & lastRow)
Whereas this line is testing column AI:
If rngCell.Offset(, 35).Value <> "Yes"
Note <> means Not Equal as opposed to =
So perhaps you wanted:
If rngCell.Offset(, 35).Value = "Yes"
Consider the following re-write.
Option Explicit
Public Sub NewItems() 'c As Range) 'I have commented out parameter which isn't currently used.
Dim rngBurnDown As Range ' not used but also not declared
Dim objWorksheet As Worksheet
Dim rngNewItems As Range
Dim rngCell As Range
Dim strPasteToSheet As String
Dim objNewSheet As Worksheet
Dim lastRowTargetSheet As Long
Set objWorksheet = ThisWorkbook.Sheets("Sheet1")
Dim lastRow As Long
lastRow = objWorksheet.Cells(Rows.Count, "A").End(xlUp).Row
Set rngNewItems = objWorksheet.Range("A5:A" & lastRow)
Dim copiedRange As Range 'for union
For Each rngCell In rngNewItems.Cells
'Debug.Print rngCell.Address 'shows where looping
If rngCell.Offset(, 35).Value = "Yes" Then
Set objNewSheet = ThisWorkbook.Sheets("Sheet1" & rngCell.Value)
Dim nextTargetCell As Range
lastRowTargetSheet = objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row
Set nextTargetCell = objNewSheet.Range("A" & lastRowTargetSheet)
rngCell.EntireRow.Copy nextTargetCell
Set objNewSheet = Nothing 'clear inside loop as you are setting in loop
lastRowTargetSheet = 0
Set nextTargetCell = Nothing
End If
Next rngCell
objWorksheet.Cells(1, 1).Select
End Sub
As for your lettering:
There are lots of examples online to generate these. Here is one way, by #harfang, from here:
Sub List_A_to_ZZZZ()
Dim i As Long
For i = 1 To 20 ' I have shortened this QHarr. Original end was 475254 ' ColXL("ZZZZ")
Debug.Print Right("---" & XLcL(i), 4)
Next i
End Sub
Function XLcL(ByVal N As Long) As String
Do While N > 0
XLcL = Chr(vbKeyA + (N - 1) Mod 26) & XLcL
N = (N - 1) \ 26
Loop
End Function
Function ColXL(ByVal abc As String) As Long
abc = Trim(Replace(UCase(abc), "-", ""))
Do While Len(abc)
ColXL = ColXL * 26 + (Asc(abc) - vbKeyA + 1)
abc = Mid(abc, 2)
Loop
End Function
I am trying to copy data from one workbook to another.
my source workbook, contains data with 722 rows. but the code is copying only 72 rows.
While I was debugging, in siiurcewkbk, I could see 722 rows being selected but then in destwkb its just 72 rows being pasted.
also, the column in my sourcewb is in AK and I want them to be pasted in column A of destwb.
Could anyone help me to rectify this issue.
Sub Extract()
Dim x As Workbook
Dim y As Workbook
Dim Val As Variant
Dim filename As String
Dim LastCell As Range
Dim LastRow As Long
CopyCol = Split("AK", ",")
LR = Cells(Rows.Count, 1).End(xlUp).Row
LC = Cells(1, Columns.Count).End(xlToLeft).Column
LCell = Activewindow.RangeSelection.SpecialCells(xlCellTypeLastCell).Address
LCC = Activewindow.RangeSelection.SpecialCells(xlCellTypeLastCell).Column
lcr = Activewindow.RangeSelection.SpecialCells(xlCellTypeLastCell).Row
Set y = ThisWorkbook
Dim path1, Path2
path1 = ThisWorkbook.Path
Path2 = path1 & "\Downloads"
Set x = Workbooks.Open(filename:=Path2 & "\Red.xlsx")
For Count = 0 To UBound(CopyCol)
Set temp = Range(CopyCol(Count) & "1:" & CopyCol(Count) & lcr)
If Count = 0 Then
Set CopyRange = temp
Else
Set CopyRange = Union(CopyRange, temp)
End If
Next
CopyRange.Copy
y.Sheets("All").Paste y.Sheets("All").Range("A4")
Application.CutCopyMode = False
x.Close
End Sub
anylead would be helpful.
If you are just coping one column of data from one worksheet to another column in another worksheet there is a lot easier way of doing it.
Does the code below help? Sorry if I've misunderstood your requirements ...
Sub Extract()
Dim Path2 As String '** path to the workbook you want to copy to ***
Dim X As Workbook '*** WorkBook to copy from ****
Dim Y As Workbook '** WorkBook to copy to
Set X = ActiveWorkbook '** This workbook ****
Path2 = "C:\test" '** path of book to copy to
Set Y = Workbooks.Open(filename:=Path2 & "\Red.xlsx")
X.Sheets("From").Range("A:A").Copy Destination:=Y.Sheets("ALL").Range("A1")
Application.CutCopyMode = False
Y.Save
Y.Close
End Sub
Try this, I commented out some lines that were doing nothing as far as I can see because I'm strict about code. Also I added some Dim statements because I always write code with Option Explicit at the top of module, this is there to help the programmer as it traps hidden compile errors.
The solution to your problem is in the lines
Dim rngLastCell As Excel.Range
Set rngLastCell = Range(CopyCol(Count) & "65535").End(xlUp)
so what we're doing here is go to the last line of the sheet on row 65535 (I know later versions have more rows but this number is fine) and then we say End(xlUp) which logically means go up this column until you find some text which will be the bottom row of your block of data.
Just underneath I changed the syntax of the Range statement which is very flexible so one call Range with a string like Range("A1:B3") or one can call Range with two arguments each of them cells, so Range(Range("A1"),Range("B3")).
Option Explicit
Sub Extract()
Dim x As Workbook
Dim y As Workbook
Dim Val As Variant
Dim filename As String
Dim LastCell As Range
Dim LastRow As Long
Dim CopyCol
CopyCol = Split("AK", ",")
'* LR is never used
'LR = Cells(Rows.Count, 1).End(xlUp).Row
'* lc is never used
'lc = Cells(1, Columns.Count).End(xlToLeft).Column
'* LCell is never used
'LCell = ActiveWindow.RangeSelection.SpecialCells(xlCellTypeLastCell).Address
'* LCC is never used
'LCC = ActiveWindow.RangeSelection.SpecialCells(xlCellTypeLastCell).Column
Dim lcr
lcr = ActiveWindow.RangeSelection.SpecialCells(xlCellTypeLastCell).Row
Set y = ThisWorkbook
Dim path1, Path2
path1 = ThisWorkbook.Path
Path2 = path1 & "\Downloads"
Set x = Workbooks.Open(filename:=Path2 & "\Red.xlsx")
Dim Count As Long
For Count = 0 To UBound(CopyCol)
Dim rngLastCell As Excel.Range
Set rngLastCell = Range(CopyCol(Count) & "65535").End(xlUp)
Dim temp As Excel.Range
'Set temp = Range(CopyCol(Count) & "1:" & CopyCol(Count) & lcr)
Set temp = Range(CopyCol(Count) & "1", rngLastCell)
If Count = 0 Then
Dim CopyRange As Excel.Range
Set CopyRange = temp
Else
Set CopyRange = Union(CopyRange, temp)
End If
Next
CopyRange.Copy
y.Sheets("All").Paste y.Sheets("All").Range("A4")
Application.CutCopyMode = False
x.Close
End Sub
CopyCol = Split("AK", ",") is Array("AK")... why?
For Count = 0 To UBound(CopyCol) ... Next runs from 0 to 0 (one cycle).
to put it in an shorter sub, I recommend something like this:
Sub Extract()
Dim path1 As String
path1 = ThisWorkbook.Path & "\Downloads"
Dim CopyCol As String
CopyCol = "AK"
With Workbooks.Open(filename:=path1 & "\Red.xlsx")
With .ActiveSheet
.Range(.Cells(1, CopyCol), .Cells(.Rows.Count, CopyCol).End(xlUp)).Copy ThisWorkbook.Sheets("All").Range("A4")
End With
.Close
End With
End Sub
My overall goal here is to grab the values and row indices of three different columns on the original spreadsheet, evaluate them, and then save them to a new spreadsheet. I am wanted to accomplish this by using a macro initiated by a button on the original spreadsheet.
The plan to accomplish this was to
create a Range for each column
Loop through the most significant Range to grab and evaluate the each cell value
perform nested loops within the first loop to further evaluate the other two Ranges and grab their values
assign values to variables
create the new spreadsheet from a template
write the values to the respective columns
save the new spreadsheet
When I run the code below I get the error listed below. I'm confused because I thought this is how you reference an entire column:
Sub Transfer2NewWorkbook()
Dim currentsheet As String
Dim newsheet As String
Dim analysisDate As String
Dim initial As String
Dim aInitial() As String
Dim analystInit As String
Dim batchNo As String
Dim wb As Object
Dim dataRangeA As Range, dataRangeB As Range, dataRangeI As Range
Set dataA = CreateObject("Scripting.Dictionary")
' Grab and Create filenames
currentsheet = ActiveWorkbook.Name
newsheet = currentsheet & "-" & "uploadable"
' Grab data from original spreadsheet
analysisDate = ActiveWorkbook.Sheets(1).Cells(1, 9).Value
initial = ActiveWorkbook.Sheets(1).Cells(1, 2).Value
aInitial = Split(initial, "/")
analystInit = aInitial(1)
Set dataRangeA = Range("A4:A").Select ' <-- Line causing error
Set dataRangeB = Range("B4:B").Select
Set dataRangeI = Range("I4:I").Select
For i = 1 To dataRangeA.Rows.Count
dataA.Add Key:=i, Item:=dataRangeA.Cells.Value
Next i
Set wb = Workbooks.Add("C:\Users\dalythe\documents\uploadtemp.xlsx")
ActiveWorkbook.Sheets(1).Cells(3, 2).Value = analysisDate
ActiveWorkbook.Sheets(1).Cells(3, 4).Value = analystInit
ActiveWorkbook.SaveAs (newsheet & ".xlsx")
End Sub
try this:
Set dataRangeA = Range("A:A").Select
Set dataRangeB = Range("B:B").Select
Set dataRangeI = Range("I:I").Select
For i = 4 To dataRangeA.Rows.Count
dataA.Add Key:=i, Item:=dataRangeA.Cells.Value
Next i
After removing the .Select, my ranges were accepted.
Set dataRangeA = Range("A:A")
Set dataRangeB = Range("B:B")
Set dataRangeI = Range("I:I")
For i = 4 To dataRangeA.Rows.Count
dataA.Add Key:=i, Item:=dataRangeA.Cells.Value
Next i
Thanks for the input YowE3k. Now I have to think on how I want my loop to end. Because doing it the way I have it above will cause it to run out of memory. The spreadsheet will not have a "predefined" number of rows. I guess I will have to have the user type "End" in the cell of the last row or something.
Your problems with the particular line throwing the error are caused by two things:
"A4:A" is not a valid address in Excel. You can either use "A:A" for the entire column or define the end of the range, e.g. "A4:A272".
The Range.Select method does not return an object, so Set dataRangeA = Range("A4:A").Select is effectively Set dataRangeA =.
To fix your specific error, you could do something like:
Set dataRangeA = Range("A4", Cells(Rows.Count, "A").End(xlUp))
However, using unqualified Cells and Range and Rows is a dangerous habit to get into once you have more than one worksheet / workbook being used in your code, because those objects default to referring to the ActiveSheet in the ActiveWorkbook and that may not be the one you are expecting it to be.
The code below ensures that each object is qualified, plus makes some other improvements to your code (such as the inevitable out-of-memory error that would arise in populating the Dictionary).
Sub Transfer2NewWorkbook()
Dim currentsheet As String
Dim newsheet As String
Dim analysisDate As String
Dim initial As String
Dim aInitial() As String
Dim analystInit As String
Dim batchNo As String
Dim wb As Object
Dim dataRangeA As Range, dataRangeB As Range, dataRangeI As Range
Dim dataA As Object ' declare this, unless you have declared it at a higher
' level scope
Set dataA = CreateObject("Scripting.Dictionary")
' Grab and Create filenames
currentsheet = ActiveWorkbook.Name
newsheet = currentsheet & "-" & "uploadable"
'Use a With block to avoid having to constantly refer
' to "ActiveWorkbook.Sheets(1)"
With ActiveWorkbook.Sheets(1)
' Grab data from original spreadsheet
analysisDate = .Cells(1, 9).Value
initial = .Cells(1, 2).Value
aInitial = Split(initial, "/")
analystInit = aInitial(1)
Set dataRangeA = .Range("A4", .Cells(.Rows.Count, "A").End(xlUp))
Set dataRangeB = .Range("B4", .Cells(.Rows.Count, "B").End(xlUp))
Set dataRangeI = .Range("I4", .Cells(.Rows.Count, "I").End(xlUp))
'This loop is making every entry in the Dictionary contain the value of
'every cell in the range - i.e. each of the 1048573 entries in the Dictionary
'would have contained an array which was dimensioned As (1 To 1048573, 1 To 1)
'For i = 1 To dataRangeA.Rows.Count
' dataA.Add Key:=i, Item:=dataRangeA.Cells.Value
'Next i
Dim cel As Range
For Each cel in dataRangeA
dataA.Add Key:=cel.Row, Item:=cel.Value
'or
'dataA.Add Key:=cel.Row - 3, Item:=cel.Value
'if you wanted A4's value to have a key of 1
Next
'Note: If you just wanted an array of values, you could have used
' Dim dataA As Variant
' dataA = Application.Transpose(.Range("A4", .Cells(.Rows.Count, "A").End(xlUp)))
'and then access each value using dataA(1) for the value from A4,
'dataA(2) for the value from A5, etc.
'This then gets rid of the need for dataRangeA, and the need for a
' dictionary object, and the need for the loop populating the dictionary.
End With
Set wb = Workbooks.Add("C:\Users\dalythe\documents\uploadtemp.xlsx")
With wb.Worksheets(1)
.Cells(3, 2).Value = analysisDate
.Cells(3, 4).Value = analystInit
End With
wb.SaveAs newsheet & ".xlsx"
End Sub
I am using vba and I have two sheets one is named "Do Not Call" and has about 800,000 rows of data in column A. I want to use this data to check column I in the second sheet, named "Sheet1". If it finds a match I want it to delete the whole row in "Sheet1". I have tailored the code I have found from a similar question here: Excel formula to Cross reference 2 sheets, remove duplicates from one sheet and ran it but nothing happens. I am not getting any errors but it is not functioning.
Here is the code I am currently trying and have no idea why it is not working
Option Explicit
Sub CleanDupes()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim keyColA As String
Dim keyColB As String
Dim rngA As Range
Dim rngB As Range
Dim intRowCounterA As Integer
Dim intRowCounterB As Integer
Dim strValueA As String
keyColA = "A"
keyColB = "I"
intRowCounterA = 1
intRowCounterB = 1
Set wsA = Worksheets("Do Not Call")
Set wsB = Worksheets("Sheet1")
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Do While Not IsEmpty(wsA.Range(keyColA & intRowCounterA).Value)
Set rngA = wsA.Range(keyColA & intRowCounterA)
strValueA = rngA.Value
If Not dict.Exists(strValueA) Then
dict.Add strValueA, 1
End If
intRowCounterA = intRowCounterA + 1
Loop
intRowCounterB = 1
Do While Not IsEmpty(wsB.Range(keyColB & intRowCounterB).Value)
Set rngB = wsB.Range(keyColB & intRowCounterB)
If dict.Exists(rngB.Value) Then
wsB.Rows(intRowCounterB).delete
intRowCounterB = intRowCounterB - 1
End If
intRowCounterB = intRowCounterB + 1
Loop
End Sub
I apologize if the above code is not in a code tag. This is my first time posting code online and I have no idea if I did it correctly.
I'm embarrassed to admit that the code you shared confused me... anyway for the practice I rewrote it using arrays instead of looping through the sheet values:
Option Explicit
Sub CleanDupes()
Dim targetArray, searchArray
Dim targetRange As Range
Dim x As Long
'Update these 4 lines if your target and search ranges change
Dim TargetSheetName As String: TargetSheetName = "Sheet1"
Dim TargetSheetColumn As String: TargetSheetColumn = "I"
Dim SearchSheetName As String: SearchSheetName = "Do Not Call"
Dim SearchSheetColumn As String: SearchSheetColumn = "A"
'Load target array
With Sheets(TargetSheetName)
Set targetRange = .Range(.Range(TargetSheetColumn & "1"), _
.Range(TargetSheetColumn & Rows.Count).End(xlUp))
targetArray = targetRange
End With
'Load Search Array
With Sheets(SearchSheetName)
searchArray = .Range(.Range(SearchSheetColumn & "1"), _
.Range(SearchSheetColumn & Rows.Count).End(xlUp))
End With
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
'Populate dictionary from search array
If IsArray(searchArray) Then
For x = 1 To UBound(searchArray)
If Not dict.exists(searchArray(x, 1)) Then
dict.Add searchArray(x, 1), 1
End If
Next
Else
If Not dict.exists(searchArray) Then
dict.Add searchArray, 1
End If
End If
'Delete rows with values found in dictionary
If IsArray(targetArray) Then
'Step backwards to avoid deleting the wrong rows.
For x = UBound(targetArray) To 1 Step -1
If dict.exists(targetArray(x, 1)) Then
targetRange.Cells(x).EntireRow.Delete
End If
Next
Else
If dict.exists(targetArray) Then
targetRange.EntireRow.Delete
End If
End If
End Sub
Edit: Because it bothered me, I reread the code that you provided. It confuses me because it isn't written the way I'd have expected and fails unless you're checking string values only. I've added comments to indicate what it's doing in this snippet:
'Checks to see if the particular cell is empty.
Do While Not IsEmpty(wsA.Range(keyColA & intRowCounterA).Value)
'Stores the cell to a range for no good reason.
Set rngA = wsA.Range(keyColA & intRowCounterA)
'Converts the value of the cell to a string because strValueA is a string.
strValueA = rngA.Value
'Checks to see if the string is in the dictionary.
If Not dict.Exists(strValueA) Then
'Adds the string to the dictionary.
dict.Add strValueA, 1
End If
Then later:
'checks the value, not the value converted to a string.
If dict.Exists(rngB.Value) Then
This fails because the Scripting Dictionary does not consider a double to equal a string, even if they would be the same if the double were converted to a string.
Two ways to fix the code you posted, either change the line I just showed to this:
If dict.Exists(cstr(rngB.Value)) Then
Or you can change Dim strValueA As String to Dim strValueA.
Because I had the time, here's a rewrite forgoing the Dictionary and instead using a worksheet function. (Inspired by the Vlookup comment). I'm not sure which would be faster.
Sub CleanDupes()
Dim targetRange As Range, searchRange As Range
Dim targetArray
Dim x As Long
'Update these 4 lines if your target and search ranges change
Dim TargetSheetName As String: TargetSheetName = "Sheet1"
Dim TargetSheetColumn As String: TargetSheetColumn = "I"
Dim SearchSheetName As String: SearchSheetName = "Do Not Call"
Dim SearchSheetColumn As String: SearchSheetColumn = "A"
'Load target array
With Sheets(TargetSheetName)
Set targetRange = .Range(.Range(TargetSheetColumn & "1"), _
.Range(TargetSheetColumn & Rows.Count).End(xlUp))
targetArray = targetRange
End With
'Get Search Range
With Sheets(SearchSheetName)
Set searchRange = .Range(.Range(SearchSheetColumn & "1"), _
.Range(SearchSheetColumn & Rows.Count).End(xlUp))
End With
If IsArray(targetArray) Then
For x = UBound(targetArray) To 1 Step -1
If Application.WorksheetFunction.CountIf(searchRange, _
targetArray(x, 1)) Then
targetRange.Cells(x).EntireRow.Delete
End If
Next
Else
If Application.WorksheetFunction.CountIf(searchRange, targetArray) Then
targetRange.EntireRow.Delete
End If
End If
End Sub