I have exported CSV files from a Development SQL Server and another from Production.
The table (in the database) has two columns
UserID
DocumentID
both of these should be unique values.
I want to be able to verify that those two combinations (together) match the other environment.
So far I imported both CSV files in separate worksheets in Excel.
After this, I am not sure what I should do to compare these columns?
I did a little google-ing and there are so many different types of answers but not sure how to do it.
Conditional Formatting only works if I select a single column. I need to get the combination of both columns.
A quick and mildly dirty VBA-approach. I assumed your workbook consists of two worksheets, each containing two columns with headers.
Option Explicit
Sub SoftwareIsFun()
Dim wks1 As Worksheet
Dim wks2 As Worksheet
Dim dicObj As Object
Dim lastRow1 As Long
Dim lastRow2 As Long
Dim i As Long
Set dicObj = CreateObject("Scripting.Dictionary")
Set wks1 = ThisWorkbook.Worksheets(1)
Set wks2 = ThisWorkbook.Worksheets(2)
With wks1
lastRow1 = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow1
If Not dicObj.Exists(.Range("A" & i).Value) Then
dicObj.Add .Range("A" & i).Value, .Range("B" & i).Value
Else
.Range("C" & i).Value = "UserID already exists"
End If
Next i
End With
With wks2
lastRow2 = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow2
If dicObj.Exists(.Range("A" & i).Value) Then
If .Range("B" & i).Value = dicObj.Item(.Range("A" & i).Value) Then
.Rows(i).Interior.Color = vbGreen
Else
.Rows(i).Interior.Color = vbRed
End If
Else
.Rows(i).Interior.Color = vbRed
End If
Next i
End With
End Sub
What you are describing is something I do daily for my job:
Step 1
Create a 3rd column in both worksheets called "Key" where you'll concatenate the values for Column's A & B as follows:=A2&B2.
Now autofill your rows in column C with the previous formula you've written.
Step 2
Remove duplicates found in this column you've created, this will effectively preserve pairs and prevent information loss when removing duplicate values. (Data Tab -> Remove Duplicates -> Select column C as the criteria to remove them).
Step 3
Make a Vlookup in a 4th column in your first worksheet, the function takes 4 parameters: =vlookup(C2, <4th column of the other worksheet (select entire range from row 2 to end)>, 1, 0) and autofill your rows with the formula.
If you aren't yet familiar with vlookup yet I strongly advice you watch a brief tutorial on its usage, it is an essential tool to compare data.
Any value that matches will be displayed, whereas an #N/D error will print for those which don't match between the 2 tables.
Related
Attempting to write some vba but not having much luck. I have column A with a whole list of values that I am counting and looping through. For Each value in column A, there can be a match in range C:D. If a value in column A matches a value in column C. I want to insert the corresponding value in column D below the Column A value. I am not too certain on what my IF then statement should look like. I have my counter and loop... I am just unsure where to go with the middle portion of the code.
Sub SetListOrder()
Dim wp As Worksheet
Dim ef As Long
Set wp = Workbooks("Packing Slip FIXED").Worksheets("Locate Order")
ef = wp.Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To ef
IF (UNSURE WHAT TO PLACE HERE!) THEN
Next i:
End Sub
Edit: adding sample data
Sample Data screenshot
In this example, I would like to insert a new row under the value in "A" where A=C. ie. Range in column "A" = Range in Column "C". I would like to then insert the value from "D". The new order in rows 4-6 would be:
Range
Order Group 1
2604291
I already have written the code to manually move my sheets around to follow the specific order once I am able to get the names in said order.
I agree with #BigBen that the simpler approach would be to insert a formula in column D that only replicates the column A value when a match is detected. Such a formula would probably look like the following -
=IF($A1=$C1,$A1,"")
This would be copied into cell D2 of your column and copied down as far as needed.
However, if you did want to achieve this with VBA and I have noted you used the word insert a value (as opposed to simple enter a value or copy & paste a value) then this could be your approach -
Sub SetListOrder()
Dim wp As Worksheet
Dim ef As Long
Dim i As Long
Set wp = Workbooks("Packing Slip FIXED").Worksheets("Locate Order")
ef = wp.Range("A" & Rows.Count).End(xlUp).Row
For i = ef To 1 Step -1
If wp.Range("A" & i).Value = wp.Range("C" & i).Value Then
wp.Range("D" & (i + 1)).Insert xlShiftDown
wp.Range("D" & (i + 1)).Value = wp.Range("A" & i).Value
Else
End If
Next i
End Sub
This approaches the problem in reverse by going up your column instead of going down. Note that by inserting your data, will cause each previous value to move down as well. If you don't want this, then simply erase the .Insert line and it will enter the value instead of inserting a cell.
Modify the below code and use:
Formula:
=IFNA(VLOOKUP(A1,$C$1:$D$5,2,0),"Missing")
VBA Code:
Option Explicit
Sub test()
Dim rngSearch As Range, rngFound As Range
Dim LastRowA As Long, LastRowC As Long, i As Long
With ThisWorkbook.Worksheets("Sheet1")
LastRowA = .Cells(.Rows.Count, "A").End(xlUp).Row
LastRowC = .Cells(.Rows.Count, "C").End(xlUp).Row
Set rngSearch = .Range("C1:D" & LastRowC)
For i = 1 To LastRowA
Set rngFound = rngSearch.Find(.Range("A" & i).Value, LookIn:=xlValues, Lookat:=xlWhole)
If Not rngFound Is Nothing Then
.Range("B" & i).Value = .Range("D" & rngFound.Row).Value
Else
.Range("B" & i).Value = "Missing"
End If
Next i
End With
End Sub
Result:
Here is a sample of the report I have:
Basically the report consists in a huge list of suppliers where among other things, I need to identify which of them have all entities (content groups) for the same country, while ignoring the "integrate" tag. Entities for each country are defined in a table separately (right).
So far I tried a combination of =SUMPRODUCT(--(ISNUMBER(SEARCH())) but always getting partially what I want.
In column C, in need:
to display YES if the supplier on that row has all entities for the mentioned country code;
to display NO otherwise;
My logic on this:
The formula/s needs to pick the country code from 1st table, then look into the 2nd table where entities are defined and check if all the entities in the content group are matching, ignoring "integrate" which is a default tag applied everywhere.
Expected result:
Try:
Option Explicit
Sub test()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim LastRowA As Long, i As Long, y As Long
Dim arr As Variant
Dim CountryCode As String
Dim rng As Range, SearchRange As Range, FindPosition As Range
Dim Appears As Boolean
'Set worksheets on variables
With ThisWorkbook
Set ws1 = .Worksheets("Sheet1")
Set ws2 = .Worksheets("Sheet2")
End With
'Set the range to search in for country codes
Set SearchRange = ws2.Range("H1:R1")
With ws1
'Find the last row of Column A sheet1
LastRowA = .Cells(.Rows.Count, "A").End(xlUp).Row
'Start loop from row 2 to last row sheet1
For i = 2 To LastRowA
'Criteria needed ( Column A - Not empty cell, Column D - Includes "Europe" & Column E - Includes "No" Columns D and E are CASE SENSITIVE)
If .Range("A" & i).Value <> "" And .Range("D" & i).Value = "Europe" And .Range("E" & i).Value = "No" Then
CountryCode = .Range("B" & i).Value
'In which column the country code found
Set FindPosition = SearchRange.Find(What:=CountryCode, LookIn:=xlValues, LookAt:=xlWhole)
'If code excist
If Not FindPosition Is Nothing Then
'Set the range to search for the groups in the column where the code is header
Set rng = ws2.Range(ws2.Cells(2, FindPosition.Column), ws2.Cells(ws2.Cells(ws2.Rows.Count, FindPosition.Column).End(xlUp).Row, FindPosition.Column))
'Split the string with comma and assing it on arr
arr = Split(.Range("A" & i).Value)
Appears = False
'Loop the arr
For y = LBound(arr) To UBound(arr)
'Check if the arr(y) start from C as all code start from C
If Left(arr(y), 1) = "C" Then
'Count how many times the arr(y) with out the comma appears in the rng
If Application.WorksheetFunction.CountIf(rng, Replace(arr(y), ",", "")) > 0 Then
'If appears the variable Appears is true
Appears = True
Else
'If does not appear the variable Appears is False & Exit the loop
Appears = False
Exit For
End If
End If
Next y
'Check Appears variable status and import value in Column C
If Appears = True Then
.Range("C" & i).Value = "Yes"
Else
.Range("C" & i).Value = "No"
End If
'If code does not excist
Else: MsgBox "Country Code not does not excist."
End If
End If
Next i
End With
End Sub
If you have a version of Excel 2013+ which has the FILTERXML function, you can use this array formula:
=IF(OR(ISNA(MATCH(FILTERXML("<t><s>"&SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A2,"Integrate",""),", ",","),",","</s><s>")&"</s></t>","//s"),INDIRECT("Table2["&B2&"]"),0))),"No","Yes")
We remove the Integrate
Create an XMLfrom the strings in Table1
Extract each element of the XML
Try to find them in the appropriate column of Table2
If we don't find one, then it has multiple countries.
Since this is an array formula, you need to "confirm" it by holding down ctrl + shift while hitting enter. If you do this correctly, Excel will place braces {...} around the formula as observed in the formula bar
If you have a version of Excel that does not have this function, and you are still interested in using excel formulas as opposed to VBA, there is another formula we can use.
I'll try to explain this best as I can, and I attached an example pic of what I'm looking for help on.
Sheet 1 represents new data that comes into the workbook, Sheet 2 represents older data saved on the work book. I would like to run a script that replaces the whole row of data in Sheet 2 from Sheet 1 based on its matching reference. If Sheet 1 has an entry that does not find a matching a reference in Sheet 2, it then pastes the new value as the last row. This would ideally run as a loop until the last row of Sheet 1.
I tried working on it & come with this code. Hope this helps.
Sub insert()
Dim i As Integer
lastrow = Sheets("sheet1").Cells(Rows.Count, 1).End(xlUp).Row
'SheetTwoEmptyRow = Sheets("sheet2").Cells(Rows.Count, 1).End(xlUp).Row
Dim rgfound As Range
For i = 1 To lastrow
Set rgfound = Worksheets("sheet1").Range("A1:A500").Find("A" & i)
If rgfound Is Nothing Then
Worksheets("sheet1").Range("A" & i, "C" & i).Copy _
Destination:=Worksheets("sheet2").Range("E" & i, "G" & i)
Else
'do nothing
End If
Next i
End Sub
[Edited]
I have a Excel workbook (.xlsx) with two worksheets (Sheet 1 & Sheet 2). Sheet 1 has 7 columns of data (each with about 70k rows) while Sheet 2 only has 5 columns with about 250-500 rows. The first column of each sheet contains a timestamp of when the data was collected in the format (yyyy-mm-dd_hh:mm:ss).
The discrepancy is that the data in Sheet 1 has data points spaced at 8 second intervals. Sheet 2, however, has sporadic data entries. There might be 4 or 5 entries that happen in a burst (say 5 second interval) and then not another entry for another couple of hours.
What I'd like to do is reorganize Sheet 2 so that the timestamps align with Sheet 1. The reason for this is that when I graph the data in sheet 1, the visualization looks appropriate because the data is evenly spaced throughout. However, I can not graph the data in Sheet 2 the same way because the data points occur at sporadic intervals.
I'm comfortable in C# and considering trying to create a program which will read in a csv file of each sheet and do the batch processing... but even there I'm a bit stuck as to what the proper procedure would be. Is there a way this can be handled directly in Excel? Any advice would be welcome.
A bit of background. I tested this on three sheets. First sheet has 100k dates with 8-second intervals. Second sheet, I have 5 columns of 300 data points, with first column containing the dates with sporadic intervals. I've decided against mangling the second sheet so my output is in a third sheet for testing purposes.
Our logic is locating the largest value that's smaller than our target date. This way, we're inside the 8 seconds between this located date and the next one. We then get that value's row from the first sheet, then we use that row as the same row number in our results sheet. We then "transfer" the values from the second sheet to the proper row in the results sheet.
Runtime is negligible on my machine. Hopefully, this runs for you properly as well. Kindly test on a copy of your workbook.
Sub Align()
Dim RefWS As Worksheet, ListWS As Worksheet, ResWS As Worksheet
Dim RngOne As Range, RngTwo As Range
Dim RngVal As Variant, Elem As Variant
Dim LRowOne As Long, LRowTwo As Long, LRowThree As Long
Dim LocRow As Long, RowCt As Long
Dim PopRng As Range, StartRow As Long
With ThisWorkbook
Set RefWS = .Sheets("Sheet1") 'Modify as necessary.
Set ListWS = .Sheets("Sheet2") 'Modify as necessary.
Set ResWS = .Sheets("Sheet3") 'Modify as necessary.
End With
LRowOne = RefWS.Range("A" & Rows.Count).End(xlUp).Row
LRowTwo = ListWS.Range("A" & Rows.Count).End(xlUp).Row
'Make sure to change based on whether you have headers or not.
Set RngOne = RefWS.Range("A1:A" & LRowOne) 'Modify as necessary.
Set RngTwo = ListWS.Range("A1:A" & LRowTwo) 'Modify as necessary.
RngVal = RngTwo.Value
'Change RowCt to 2 if you have headers.
RowCt = 1
For Each Elem In RngVal
LocRow = Application.Match(CDbl(Elem), RngOne, 1)
ResWS.Range("A" & LocRow & ":E" & LocRow).Value = ListWS.Range("A" & RowCt & ":E" & RowCt).Value
RowCt = RowCt + 1
Next Elem
'Autopopulate.
With ResWS
LRowThree = .Range("A" & Rows.Count).End(xlUp).Row
Do
StartRow = .Range("A" & LRowThree).End(xlUp).Row
If StartRow > 1 Then StartRow = StartRow + 1
Set PopRng = .Range("A" & StartRow & ":E" & LRowThree)
.Range("A" & LRowThree & ":E" & LRowThree).Copy
PopRng.PasteSpecial xlPasteValues
LRowThree = StartRow - 1
Loop Until StartRow = 1
End With
Application.CutCopyMode = False
End Sub
It's also important to note that if two values are matched, it's going to get the latest value rather than the closest one. Let me know first what happens to your data after running this.
EDIT: Code updated as per chat.
I have an issue when trying to use Union(Range, Range). I am trying to copy certain rows from one worksheet and paste them in a new file. My issue is that the Union isn't adding on more rows to the range; it returns the original range. If I flip the order of the parameters, it returns only the .Rows(i + 1) row. My test data has 2 rows that it should copy. The row count at the end is 1. What am I doing wrong?!
Dim lastRow, i As Long
Dim CopyRange As Range
lastRow = ActiveSheet.Rows.count
With Sheets(ActiveSheet.Name)
lastRow = .Range("A" & .Rows.count).End(xlUp).Row
For i = 2 To lastRow
Dim endTime As Date
endTime = DateValue(Trim(.Range("E" & i).Value))
If endTime = Date - 1 Then
If CopyRange Is Nothing Then
Set CopyRange = .Rows(i + 1)
Else
Set CopyRange = Union(CopyRange, .Rows(i + 1))
End If
End If
Next
End With
CopyRange.Copy
Actually CopyRange contains a number of separate ranges (areas). See here for more information.
When you make Union operation with separate rows (I mean that there is another row beetween them) it doesen't actually add Row, but add new Area. So, if you add MsgBox CopyRange.Areas.Count, you will see count of areas (if you will add MsgBox CopyRange.Rows.Count it will get you uncorrect result in case of many areas - it will get count of rows in first area).
As a conclusion, your code works well for me, and should works well for you. You can add CopyRange.Select line before CopyRange.Copy and set breakpoint on this line. You will see that union works well