Excel VBA: Finding the last row of a column full of duplicates, but NOT the end of the entire column - vba

I have a large datasheet, where each row has a column that gives it a unique identifier, like so:
Row Identifier Value
1 A 3
2 A 4
3 A 7
4 B 1
5 B 3
6 B 0
7 C 9
I want to be able to find the row number of the last duplicated identifier in a range. So, for example, if the identifier "B" was some unknown number of rows long, and I wanted to find the number of the last row that had the column identifier "B," how would I do so?
So far I've come up with code to select the row of the FIRST identifier:
' Select first row where first instance of <B> exists:
With ActiveWorkbook.ActiveSheet
Set First_B_Row = .Range("A:A").Find(What:="B", LookIn:=xlValues)
End With
Dim First_B_RowNumber As Long
First_B_RowNumber = First_B_Row.Row
ActiveWorkbook.ActiveSheet.Rows(First_B_RowNumber).Select
But, I want to be able to find the row number of the LAST identifier in a column full of them. Any ideas?

You are absolutely close. Instead of searching top to bottom, then search in reverse like this:
With ActiveWorkbook.ActiveSheet
Dim Last_B_RowNumber As Long
Last_B_RowNumber = .Range("A:A").Find(What:="B", After:=[A1], _
SearchDirection:=xlPrevious).Row
End With
Above code will find the last occurrence of B in Column A and assigns it's row number to a variable.
Your just missing the SearchDirection argument.

Related

How to stack multiple do loops in VBA

The aim is to match two tables accroding to some specific words.
There are two tables each with 3 colums and rows(see pic).
The value A2 (table 1) are being searched range A(table 2 ). That search of this value in table 2 range A shall continue until either the value is found in table 2 range A or the loop stops when a certain Cell (e.g. A30) is reached.For case 1, if the value in table 1 A2 is found in range A in table 2, the second value (e.g.in A3 table 1) shall be taken to search for that value in table 2 range A and so on until a sertain cell is reached again.For case 2, if the value A2 (table1) cannot be found in the given range A (table2), the value in the next colum B2 shall be search for in range B(table 2) until a certain cell is reached. If this isnt successfull as well the next step is to look for the value of C2(table1) in range C(table2).
The issue is to get the do loops in the right positions so as to the search of the values (table 1) in table 2 starts always with the values in Range A (table 1) when that value ( table 1) is found.
Update: Where I am stuck is to get the multiple Do-loops right. I guess I need 3 do-loops and my problem is to get the 3rd. do-loop (the very inner one) which does the checking of the values between the tables to jump to the very first do-loop after the value in question (table1) has been found in table 1. In other word, when the value A1 in table 1 is found the do-loop goes one row further to A2 and starts again. If nothing is found in table 2, pick up the value in B2(table1) and search again but in range "B" table 2.
I have also tried to include the command "loop until" when a certain cell number e.g cells(10,1) is reached. I guess here is also a buck init.
Sub Import_Klicken()
Dim wp As Workbook
Dim ws As Workbook
Dim c As Long, r As Long, rng As Range
Dim w As Integer
Dim t As Integer
Set ws = Workbooks.Open("C:\Users\Yavuz\Desktop\a.xlsx")
Set wp = Workbooks.Open("C:\Users\Yavuz\Desktop\t.xlsx")
Do
w = w + 1
i = i + 1
t = 0
Do
t = t + 1
If ws.Sheets("Tabelle1").Cells(i, w).Value = wp.Sheets("Tabelle2").Cells(t, w).Value Then
wp.Sheets("Tabelle2").Cells(t, w).Copy
Exit Do
End If
Loop Until wp.Sheets("Tabelle2").Cells(t, w).Value = treu
i = 0
Loop

Compare two sheets using ID column

I am looking to do a comparison of 2 sheets in a workbook in Excel 2013. Due to the number of records VLOOKUP and other formulas have been slow so I thought I would try VB to see if this was a quicker solution.
What I would like to do is compare each record by ID and highlight and mismatches in red. Due to the column names and position being different, I would also like to do the cell comparison on each record by specifying the column names to compare against. Finally, I would like to total the mismatches for each column into a 3rd sheet.
For example:
Sheet 1:
ID Col1 Col2 Col3 Col4
1 1 1 1 1
2 2 2 2 1
3 3 3 3 3
4 4 4 4 4
Sheet 2:
DBID Col1 Col2 Field Col3
1 1 1 1 1
2 2 2 2 2
4 4 4 4 4
3 3 3 3 3
So in the above example I would only like to Col4 compared with Field column and only see the Field column for ID 2 highlighted as an error with ID records 3 and 4 ignored because they match and are just in different positions in the file.
I would normally sort on ID instead of picking out a particular ID, but conscious that there could be records missing which means the data would be misaligned.
At the moment I have found this code which will highlight the mismatches in red, but matches cell by cell without taking into consideration that the columns and records might not be in the same order.
Sub RunCompare() 'Call the compareSheets routine Call compareSheets("Sheet1", "Sheet2") End Sub
Sub compareSheets(shtBefore As String, shtAfter As String) Dim mycell As Range Dim mydiffs As Integer 'If current cell is not a date then proceed (else skip and go to next), then 'if not same as corresponding cell in sheet After, 'mark as yellow and repeat until entire range is used For Each mycell In ActiveWorkbook.Worksheets(shtAfter).UsedRange If Not IsDate(mycell) Then
If Not mycell.Value = ActiveWorkbook.Worksheets(shtBefore).Cells(mycell.Row, mycell.Column).Value Then
mycell.Interior.Color = vbRed
mydiffs = mydiffs + 1
End If End If Next 'Display a message box stating the number of differences found MsgBox mydiffs & " differences found", vbInformation ActiveWorkbook.Sheets(shtAfter).Select End Sub
I am assuming that the ID is unique.
You have basically two solutions, with and without macro.
With Macro Logic can be as follows :
Get the first (Unique) column of first sheet
Loop through the first (Unique) column and find the matching row in second sheet
Compare between cells in that row with the first row of first sheet
Repeat the same steps for all rows
Also do a check to see if both sheets have same number of rows and columns; and no rows are duplicated.
Non Macro Solution :
Use VLookup Function to lookup for the row matching the value and do an equal comparison formula in a new sheet as
=IF(Sheet1!B1=VLOOKUP(Sheet1!A1,Sheet2!A:Z,2,FALSE),"Same","Different")
Note that you will need to increment the row number and column name I have highlighted in first column of the third (Answer) sheet.
Once you have values, you can use conditional formatting to highlight Different to Red

How to Find the Length of a Column in VBA with a Variable Last Row

I'm a beginner to vba and hope to use it in order to automate a process. I have a computer program that provides me an excel spreadsheet, where the amount of data in the columns can change. For example, I could have a column of length 9 one time:
1
3
2
4
24
23
432
55
2
Or a column of length 5 (note: actual column sizes are usually in the thousands):
1
2
3
4
8
I want to write code that will grab this column, not knowing how long the column will be. Something like:
Dim list1 As Array
'I don't know how to find the upper bound
list1 = Range("A1:A" & Upper Bound).Value
Any help is appreciated. Thanks!
If you are working with constant values in these columns and are working with larger amounts of cells in these columns, it could be useful to use the count function:
dim x As Long
x = Worksheets(*sheet name*).Range(*column range*).Cells.SpecialCells(xlCellTypeConstants).Count
x is being passed the number of non-empty cells in your column. So you may want to be careful in your column range not to include any headers, if applicable.
I believe this will get you the last row. You might need to be careful if you're looking to count all values (e.g. the first couple rows are blank).
Dim lastRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
To get the data from column A into a 2d variant array, use the following:
Dim vA As Variant
vA = [a1:index(a:a,counta(a:a))]
This assumes that there are no blank cells within the data, and that the data starts in row 1.

VBA Match Against a Column With Duplicate Values

I have an excel range I'm using as a database. The first column is sorted in ascending order by date, but there can be multiple records with the same date, e.g.
A B
1 15-Apr-2015 Carrot
2 15-Apr-2015 Yamagobo
3 16-Apr-2015 Turnip
4 17-Apr-2015 Parsnip
5 17-Apr-2015 Rutabaga
6 17-Apr-2015 Radish
7 18-Apr-2015 Daikon
(The stuff in column A are formatted dates, not text strings.)
What I'd like to get is the first record that has a date greater than or equal to the one I'm searching for, so I have:
Dim searchDate As Date
searchDate = CDate("4/17/15")
Dim searchRange As Range
Set dbRange = Worksheets("My DB").UsedRange
Dim v As Variant
v = Application.Match(CLng(searchDate), dbRange.columns(1), 1)
I expect v to now contain the index of the first row with 17-Apr-2015 in column A, 4. Instead, it seems to be returning the last row with 17-Apr-2015, 6.
Two questions:
1) Is there a way to use Match() (or any other function) to point at the first entry that matches, instead of the last?
2) Match() freaks out if I give it a Date type as its match parameter (hence the CLng() conversion). Is this to be expected, or am I doing something stupid?
Thanks.
Try to use Find instead of Match
To get the cell:
set MyRange = dbRange.Columns(1).Find(searchDate)
To get just the row:
MyRow= dbRange.Columns(1).Find(searchDate).row

How to copy variable range vba

My table contains variable number of rows and three columns (A:C) that I am interested in
A B C D
1 xx xx xx xxx
2 ....
3 ....
4 ...
I need to copy from WorkSheet1 to WorkSheet2
ws2.Range("A1").Value = ws1.Range("A1:C4").Value
The problem is that I do not want to hardcode C4 , because it can be C5 or C20 . How can I account for possible variable number of rows.
PS : I cannot use Range("A1").CurrentRegion because this will select more columns than needed, i.e. column D values will also get selected. Although it will select the correct number of rows
There is more than one solution to most problems, but since CurrentRegion method returns the right number of rows (but the wrong number of columns), you could do something like this assuming you always need THREE columns.
Dim rng as Range
Set rng = ws1.Range("A1").CurrentRegion.Resize(,3)
ws2.Range(rng.Address).Value = rng.Value
I'm making an assumption that the last row in D will be equal to or less than the last row of A:C. I'm also assuming that the last row is determined by the last row that contains data.
Sub CopyColumnAtoC()
Dim lastRow As Long
lastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
ThisWorkbook.Worksheets(1).Range("A1:C" & lastRow).Copy
ThisWorkbook.Worksheets(2).Range("A1:C" & lastRow).PasteSpecial xlPasteValues
End Sub
You can specify just columns in a range. So
Sheet2.Range(Sheet1.Range("A:C").Address).Value = Sheet1.Range("A:C").Value
will copy columns A through C regardless of the rows in each column, i.e. if Column A has 8 rows, B has 6, and C has 11 it will still work.