Compare two sheets and find differences, copy to third sheet - vba

I have been trying to compare two sheets. The sheets are versions, one made in August, the other in September. In Sheet1, column C I have a unique ID that could also be in sheet 2, but could also be not present. On the other hand, I could have NEW ID's in sheet 2, that are not present in Sheet1.
I am trying to:
Identify IDs not in "other" sheet, copy entire row to sheet3
Check if C-column value exists in other sheet, then it has to find
the differences in THOSE two rows, 12 columns out
Example, in sheet1:
ID Jan Feb Mar Apr May
14578596 125 125 125 0 10
22345697 10 10 10 10 20
12563654 150 150 75 75 75
85745896 890 890 890 890 790
and in sheet 2:
ID Jan Feb Mar Apr May
14578596 125 125 125 0 10
12563654 150 150 75 75 75
85745896 890 890 790 890 790
87544545 0 0 0 0 10
In sheet 3, it should copy over the newly added ID 87544545 and all the values in the following columns. It should copy over the ID's 22345697 entire row as well, as being non-existing in the other sheet is considered a difference.
For the others, that exist in both sheets, it should Take "Jan-Jan" and return the difference value. So it should lookup if "ID" exists in other sheet, if it does, compare the Jan-Feb-Mar with each other. Note that ID's are NOT in the same position in the sheets. With ID 85745896 it would return:
ID Jan Feb Mar Apr May
85745896 0 0 100 0 0
I have tried to look at topics such as
Compare data from 2 sheets and find mismatches
and
Check if two rows are the EXACT SAME in MS Excel but can't seem to make them work for my challenge here.

Sub compare()
For i = 1 To last_cell_mainSheet
For j = 1 To last_cell_sheet2
If Worksheets("main_sheet").Range("a" & i).Value = Worksheets("sheet2").Range("a" & j).Value
Then
Worksheets("main_sheet").Range("C" & i).Value = Worksheets("sheet2").Range("b" & j).Value
End If
Next j
Next i
End Sub

The easiest way to solve this is with excel formulas. (if you only want to do it once, or occasionally.) If you need to repeat if often (or have massive amounts of data) use VBA>
You will need to find out about VLOOKUP and IF and ISNA.
Essentially you can add a column to both sheets that looks up the ID in the other sheet and returns Y or N if it is found or not.
You formaula will be something like:
=IF(ISNA(VLOOKUP(MyIDCell,TheTableInTheOtherSheet, 1, false)),"N","Y")
TheTableInTheOtherSheet is a range starting with the ID column (and only neededing one column)
Do the Jan-Jan bit.
Again use a vlookup formula column on sheet1 to get the value of Jan from sheet2. The add a formula to compare them.
You formula will be something like:
=VLOOKUP(MyIDCell,TheTableInTheOtherSheet, 2, false)
TheTableInTheOtherSheet is a range starting with the ID column (and two columns wide)
2 get the second column value
Once you have the data you can sort or filter to reduce the list ot thsoe you need to copy to sheet 3 (best to sort). Then copy and paste them.

Related

What are the changes needed in my existing Excel VBA code to meet this specific task?

I am using Excel 2016. I need to transpose data from several workbooks (each containing different amount of worksheets). All the worksheets are in the same format and all the columns that need to be transposed for each worksheet begin at the same place (say, column D). However, each worksheet can contain a different number of columns to be transposed (that is, Worksheet 1 may have columns D to E, Worksheet 2 may have Cols D to G, and so on...).
I already have a VBA code that I can run to do the job (more on this below) but my main problem is that I need to manually change the code each time I need to run it on a Worksheet because the range of data that I need to transpose differ from worksheet to worksheet.
Here is my existing VBA Code:
Sub TransposeColumns()
Dim i As Long
Dim RW As Long
With Sheets("ORIGINAL")
For i = 4 To 10 'CHANGE VALUE HERE; MAX NUMBER SHOULD BE NUMBER OF COLUMNS IN ORIGINAL WORKSHEET
RW = 1 + Sheets("output").Range("A65536").End(xlUp).Row
.Range("A2:C74").Copy Sheets("output").Range("A" & RW) 'CHANGE RANGE VALUES
.Range(.Cells(2, i), .Cells(74, i)).Copy Sheets("output").Range("D" & RW) 'CHANGE RANGE VALUES
Sheets("output").Range("E" & RW).Resize(73) = .Cells(1, i).Value
'CHANGE RESIZE VALUE;RESIZE VALUE SHOULD BE MAX RANGE VALUE - 1
Next i
End With
End Sub
Here is Original data from Workbook 1 - Worksheet named "Feb 2015":
col A col B col C col D
HOTEL RATING PLAN 22/08/2014
EBA 3 AI 88
VER 3 AI 85
TRO 3 AI 91
And this is what I get when running my existing VBA code on that Worksheet:
EBA 3 AI 88 22/08/2014
VER 3 AI 85 22/08/2014
TRO 3 AI 91 22/08/2014
Now, in that same Workbook, I may have another Worksheet named, say, "Jun 2015" and it might look like this:
col A col B col C col D col E
HOTEL RATING PLAN 22/04/2014 25/05/2014
EBA 3 AI 69 58
VER 3 AI 80 60
TRO 3 AI 90 98
Right now, I need to run my vba code 2 times, once for each worksheet. Also I need to rename the worksheet as "ORIGINAL" as per my vba code.
I need to change the vba code so that it does the following:
(1) automatically determine the range needed to transpose the required columns (based on the fact that the columns needed to be transposed will always start from Column D)
(2) automatically add a new column to the transposed data and fill that column with the name of the worksheet
(3) the vba code should run across all worksheets in the Workbook and output all the results in one single new worksheet
So, basically here's the output I am looking for based on the examples above with a Workbook having only 2 worksheets named "Feb 2015" and "Jun 2015" respectively:
EBA 3 AI 88 22/08/2014 Feb 2015
VER 3 AI 85 22/08/2014 Feb 2015
TRO 3 AI 91 22/08/2014 Feb 2015
EBA 3 AI 69 22/04/2014 Jun 2015
VER 3 AI 80 22/04/2014 Jun 2015
TRO 3 AI 90 22/04/2014 Jun 2015
EBA 3 AI 58 25/05/2014 Jun 2015
VER 3 AI 60 25/05/2014 Jun 2015
TRO 3 AI 98 25/05/2014 Jun 2015
Note: I must also add that the number of Rows differ from worksheet to worksheet and I need the vba code to automatically take that into account too.
I am not going to write your program for you, I think you should have focussed on those parts of VBA you have yet to learn and asked them, (actually google them).
Anyway, some tips with which you can complete your task
To find out the number of rows one get a range variable, say rng one has
Debug.Print "rowcount=" & rng.Rows.Count
for column count
Debug.Print "columncount=" & rng.Columns.Count
to find an edge of a block of cells you already have an example, you start in a blank cell and head towards the block so in your code you have
Sheets("output").Range("A65536").End(xlUp).Row
which will find the lowest row of a block of cells in A column.
You can even use UsedRange which given a cell will find all the range enveloping the surrounding block.
Sheets("output").Cells(1,1).UsedRange
You are now equipped to complete your task. :)

Use V-Lookup to the cell number

So I have been given the task of comparing to worksheets in excel and if there is a match replacing the data from one cell with another, for example, I have 2 columns in 2 excel sheets, ID and name, I want to compare the IDs in sheet 1 with the IDs in sheet two and if it finds a match update the name linked with that ID.
Sheet 1
ID Name
1 Thomas
2 Jerry
Sheet 2
ID Name
3 Spike
1 Tom
So in the example above, I need the code to see that ID 1 is in both sheets and change the name in sheet 1 to match sheet 2, so that it looks like this:
ID Name
1 Tom
2 Jerry
I'm trying to use the Vlookup, which has allowed me to find out if it is existing or not, but then I don't know how to change the cell to match the existing one, here is my code so far:
Range("C2").Select
ActiveCell.Formula = _
"=IF(ISNA(VLOOKUP([#[ID]], 'Sheet2'!A:B,1,FALSE)), ""New"", ""Existing"")"
Do While Len(Range("A" & r).Formula) > 0
If (Range("C" & r).Value = "Existing") Then
Sheets("Sheet2").Range("A" & r & ":B" & r).Copy _
Destination:=Sheets("sheet1").Range("A" & r & ":B" & r)
Else
End If
I need to be able to get the cell number from the Vlookup so that I can use it in the if statement to pull in the correct data. There may be a simpler way to do this, if so I am open to changing everything.
Any help would be much appreciated.
I don't think there is a need of VBA for this task. As the names in "Sheet1" has to be updated by looking into the data in "Sheet2". Following formula can be used to find the updated names (by looking into data from the "Sheet2").
=IFERROR(VLOOKUP(A2,Sheet2!A2:B3,2,FALSE),B2)
IFERROR is used so as to retain the names which were not found in "Sheet2" data. Have a look at following screenshot for the example.
Easiest way is on a third sheet create 3 headings in row A: ID, Name and Source. Copy your data from sheet 1 into the first two columns and fill the third column with the text sheet 1. Do the same for sheet 2 but paste it below your sheet 1 data. You should end up with something like this:
ID Name Source
1 Thomas Sheet 1
2 Jerry Sheet 1
3 Spike Sheet 2
1 Tom Sheet 2
Then just create a pivot table from this data with source as the column, name as the row and a count of name for the data. It should look something like this:
Name Sheet 1 Sheet 2 Total
Thomas 1 0 1
Jerry 1 0 1
Spike 0 1 1
Tom 0 1 1
You can then sort on the Total column to find the duplicates which will have a total of two.
One other advantage of using this method is that it is quite easy to expand it to compare three or more lists.

How to define name of a range with duplicate values in VBA?

I'd like to know how to define name for a range with duplicate values and have it automatically run through a the whole table. Please see the table below.
A B
1 CODE Display
2 100 000
3 100 000
4 100 010
5 100 020
6 100 030
7 100 100
8 110 000
9 110 010
10 110 020
11 110 030
12 110 100
13 110 101
14 110 200
15 110 204
16 110 208
17 110 209
Now, I know that I can use the method Names.Add to define. However, my problem is to be able to get the name range of the duplicate values in Column A as shown in the snippet.
I want to define name of Range B2:B7 as "t_100", for example. What I can think of is to get the address range from A2:A7, offset 1 column, then use the Names.Add method to refers to B2:B7. And since A2:A7 range contains only "100", it begs the question how to get the range of a continues duplicate values.
That's my initial thought.
Filtering on a known value and then referencing the .SpecialCells(xlCellTypeVisible would be a good method of gathering the cells with duplicate column A values together. Counting to see if any particular value was the first occurrence of that value as you walked down the column would ensure that you were not unnecessarily repeating actions.
Sub t_000_name_table()
Dim rw As Long, val As Variant
With ActiveSheet
With .Cells(1, 1).CurrentRegion
.AutoFilter
For rw = 2 To .Rows.Count
val = .Cells(rw, 1).Value
If Not CBool(Application.CountIf(.Cells(1, 1).Resize(rw - 1, 1), val)) Then
.AutoFilter field:=1, Criteria1:=val
With .Offset(1, 1).Resize(.Rows.Count - 1, 1)
.SpecialCells(xlCellTypeVisible).Name = Format(val, "\t\_000")
End With
.AutoFilter field:=1
End If
Next rw
.AutoFilter
End With
End With
End Sub
I've used a shorthand name declaration statement which replies heavily on the defaults. It should come in as workbook scope and absolute cell range addressing for the Refers to:. If you wish to alter the scope or other property, you can use the MSDN VBA reference for Name Object .Add.
This should work well for non-contiguous ranges as well.

Excel Macro find and copy corresponding cell apply formula on the value

Hi I am new to VBA script. I have the following problem.
Sheet 1
Date Sum of cnt
01-04-2014 77
01-06-2014 3
01-07-2014 2
01-08-2014 1
01-09-2014 921
Sheet 2
Date count (count/sumofcout(sheet1)
01-06-2014 3
01-09-2014 4
01-09-2014 712
01-07-2014 1
01-08-2014 1
01-09-2014 205 .....
I have to search for the every single date from sheet 1 if there is match in sheet 2 , corresponding count(sheet2)/sum0fcount of that date(sheet1) should be my third column in sheet 2. Please anyone help me. I have large data multiple values of each day in a month.
Thanks in advance.
As Tim has suggested in his comment above...you can use Vlookup/Match (along with SumIF) to get your results. A formula like this (with different ranges) should do the job:
IF( ISNA(MATCH(A2,Sheet1!$A$2:$A$13,0)),"",B2/SUMIF(Sheet1!$A$2:$A$13,A2,Sheet1!$B$2:$B$13))
You can change the Ranges A2:A13, B2:B13 to adjust this according to your data

Excel VBA: Move row to a destination regardless of row count in pivot table

I am new to VBA and have very basic knowledge. I have a pivot table which calculates the count of students grouped by enrollment date and columns consists of Brand Ids
I want to move a row to the end of the pivot table and the number of rows keeps changing. I tried below code but I can use that only when number of rows in pivot table are constant. Can someone please help me to move row to the end of the table though the number of rows are not constant?
ActiveSheet.PivotTables("StudentCount").PivotSelect "'En_Date'['(blank)']", _
xlDataAndLabel + xlFirstRow, True
ActiveSheet.PivotTables("StudentCount").PivotFields("En_Date").PivtoItems( _
"(blank)").Position = 20
'In current sheet I need to move to 20 but actually 20 is not constant
ActiveSheet.PivotTables("StudentCOunt").PivotSelect "En_Date", xlButton, True
I tried below code as well but it is not working:
Dim LS as LONG
LS = ActiveSheet.PivotTable("StudentCount").TableRange2.Rows.Count
ActiveSheet.PivotTables("StudentCount").PivotSelect "'En_Date'['(blank)']", _
xlDataAndLabel + xlFirstRow, True
ActiveSheet.PivotTables("StudentCount").PivotFields("En_Date").PivtoItems( _
"(blank)").Position = "& (LS - 1)"
ActiveSheet.PivotTables("StudentCOunt").PivotSelect "En_Date", xlButton, True
Pivot Table:
Count Of Students
Date A1 A2 A3 A4 Blank Grand TOtal
blank 69 86 23 45 223
01/01/2014 2 25 3 1 31
02/01/2014 1 2 5 8 16
Grand Total 71 112 28 51 262
Hi to answer your question, you do not need VBA to do this.
The reason your pivot is behaving as such is because your Dates are actually not Dates but Dates Entered as Text. See below recreated data:
Re-entering it as actual dates will solve your problem.
So after changing the Text Dates to actual Dates, your pivot sorts your row as you like.
See below:
Hope the solution I presented helps you a bit.
Additional: If however re-entering all the dates is not convenient, try below code:
Dim i As Integer
With ActiveSheet.PivotTables("StudentCount").PivotFields("En Date")
For i = 1 To .PivotItems.Count
If .PivotItems(i) = "(blank)" Then .PivotItems(i).Position = .PivotItems.Count
Next
End With
The code above simply iterates through all the PivotItems, looks for (blanks).
It then change it's position to the last position which is equal to .PivotItems.Count.
Hope this works for you.