Compare 2 Cells and Find Missing Values in Excel - excel

I'm currently comparing 2 databases where ZIP codes have been entered manually. I need to compare the ZIP codes for hundreds of accounts in each database to check if anything is missing. I've ordered all the values in ascending order in excel but cant seem to find a quick way to check what's missing.
Column A: Database A ZIPS (The correct ZIPs)
14464, 14515, 14612, 14615, 14626
Column B: Database B ZIPS (Manually Entered)
14464, 14612, 14615, 14626
Column C: Missing ZIPs
14515
EDIT: I should have clarified, the data is stored in this manner.. each zip is not stored in a separate column, there are multiple Zips for each agent.
Image of worksheet
I know there must be a way to find this value using an excel VBA!
Thanks

Answer prior to seeing author's data format
Luckily the task is not too hard. You just need to simply use:
=IF(COUNTIF(list,value),"Output if it exists","Output if missing")
So in your case using the columns you define...
=IF(COUNTIF($B:$B,$A1),"",A1)
Then apply the formula for the length of the correct zip column.
see: https://exceljet.net/formula/find-missing-values
Example picture here

give this a go
Public Function ShowMissingZips(rngSource As Range, _
rngMatch As Range) As String
Dim colSource As Collection
Dim colMatch As Collection
Dim colOutput As Collection
Dim varSource As Variant
Dim varMatch As Variant
Dim varOutput As Variant
Dim intCounter As Integer
Dim blnMatched As Boolean
Dim strSource As String
Dim strMatch As String
Dim strOutput As String
Set colSource = New Collection
Set colMatch = New Collection
Set colOutput = New Collection
strSource = Replace(rngSource.Value, " ", "")
For Each varSource In Split(strSource, ",")
colSource.Add varSource
Next
' Clean up source data
strMatch = Replace(rngMatch.Value, " ", "")
For Each varSource In Split(strMatch, ",")
colMatch.Add varSource
Next
' Clean up match data
For Each varSource In colSource
blnMatched = False
For Each varMatch In colMatch
If varSource = varMatch Then
blnMatched = True
Exit For
End If
Next
' Note if it's not matched
If Not blnMatched Then
colOutput.Add varSource
End If
Next
' Only output if there's anything present
If colOutput.Count > 0 Then
For Each varOutput In colOutput
strOutput = strOutput & CStr(varOutput) & ", "
Next
strOutput = Left$(strOutput, Len(strOutput) - 2)
End If
ShowMissingZips = strOutput
End Function
To use it, press Alt-F11 to get to the VBA editor. Find your workbook in the project explorer (Ctrl-R if not visible) and on the menu at the top click Insert..., Module.
Paste this code in.
Go back to your workbook and assuming that you've kept the columns as before (A, B & C and with row 2 as the first data row), go to cell C2 and type
=ShowMissingZips(A2,B2)
You should see what you're after. It's not pretty and I'd normally add error handling, but it'll do for a quick fix.
When you save it, be sure to use the XLSM format (Excel 2007+) so that the VBA is retained.

Related

Is there a better way to do this? VBA script

What I have here is a tracking list, for feeding pumps. We have to account for stock levels, so I made this. When you enter a pump, into the table, nothing happens. When you put a patient's name against it, the row goes pink to indicate the pump has left our stock.
I was trying to get a script/macro together that could count the pumps that we still had (i.e the white rows, e column), and display the list (table will get quite long in future) to the user.
My code:
It loops through the c column (serial numbers) for each "cll", an if statement checks if there is anything in the cell 2 columns to the right (patient name, if there is a patient name, it means the pump has been given out) AND if there is a value in the e column (serial numbers). It displays serial numbers that fulfill the criteria in a series of message boxes.
The code works, and I'm happy to roll it out, as this isn't an overly important issue, and I'll be leaving it with a group of technophobes. However, I'm wondering, it's a little clunky?
I don't like the seperate message boxes, but I can't find any info on making an array in excel VBA, and I don't like checking the IF using the offset property.
I couldn't make checking the cll.Interior.color/colorIndex work, as excel seemed to think the cells are all the same color, regardless of what color they actually are. (?conditional formatting causing issues).
Hope this makes sense,
EDIT:
Code as text:
Private Sub CommandButton1_Click()
Dim cll As Range
For Each cll In Range("c6:c200")
If IsEmpty(cll.Offset(0, 2)) And cll.Value > 0 Then
MsgBox "Pump Serial number: " & vbNewLine & vbNewLine & cll.Value
End If
Next cll
End Sub
concatenate the serial numbers in the loop and then after the loop show the concatenated string.
find the last cell with a value and only loop to that row.
Iterate a variant array instead of the range, it is quicker
Private Sub CommandButton1_Click()
Dim cll As Variant
cll = ActiveSheet.Range("C6", ActiveSheet.Cells(Rows.Count, 3).End(xlUp).Offset(, 2)).Value
Dim str As String
str = ""
Dim delim As String
delim = ""
Dim i As Long
For i = 1 To UBound(cll, 1)
If Not IsEmpty(cll(i, 1)) And IsEmpty(cll(i, 3)) Then
str = str & delim & cll(i, 1)
If delim = "" Then delim = vbNewLine
End If
Next i
MsgBox "Pump Serial number: " & vbNewLine & vbNewLine & str
End Sub

Delete multiple variable columns mentioned in worksheet in VBA

I am trying to delete multiple columns of a newly created workbook stated in the original workbook.
The columns to be deleted are mentioned in one column and the number of column-sequences may be variable.
So far I tried to go through it with a loop which does not work currently. Furthermore, it's not a good practice, since after deletion the rows shift which makes it hard to name the correct columns up for deletion.
Currently, i am receiving an error in the For-next-loop. The Columns-Statement doesn't seem to work.
For your information: I am fairly new to VBA and programming. If you have any more tips or hints reading my code, please give me a sign, I am very happy to improve my VBA-skills.
Sub CleanPlan()
' Define columns up for deletion as variable array
' Use .Transpose to ensure one-dimensional array
Dim DelCol As Variant
DelCol = Application.Transpose(ThisWorkbook.Sheets("Export").Range("B4:B" & Cells(Rows.Count, 2).End(xlUp).Row))
' Open origin file, save as .xlsx
Workbooks.Open Filename:=ThisWorkbook.Path & "\" & ThisWorkbook.Sheets("Export").Range("B1").Value
ActiveWorkbook.SaveAs Filename:=ThisWorkbook.Path & "\name22.xlsx", FileFormat:=xlOpenXMLWorkbook
ActiveWorkbook.Close
Workbooks.Open Filename:=ThisWorkbook.Path & "\name22.xlsx"
' Delete columns from array
Dim i As Integer
For i = 1 To UBound(DelCol)
Columns("""" & DelCol(i) & """").Delete
Next i
' more code, irrelevant at this point
There must be a better practice to solve this issue. I am very thankful for any tips!
Try replacing you loop with this:
Dim i As Integer
Dim x As Long
Dim holdInt As Long
' refactor array to numbers:
For i = 0 To UBound(sortArray)
sortArray(i) = GetColumnNumber(Replace(Left(sortArray(i),2), ":", ""))
Next i
' sort array
For i = 0 To UBound(DelCol)
For x = UBound(DelCol) To i + 1 Step -1
If DelCol(x) < DelCol(i) Then
holdInt = DelCol(x)
DelCol(x) = DelCol(i)
DelCol(i) = holdInt
End If
Next x
Next i
' delete column from right to left
For i=UBound(DelCol) to 0 step -1
Columns(DelCol(i)).Delete
Next i
'-------------------------------------------------
Function GetColumnNumber(text As String) As Long
Dim r As range
Set r = range(Trim(text) & 1)
GetColumnNumber = r.Column
End Function
This will sort you array of columns' numbers, and then will go from end to start so the shift not affect column numbers.
UPDATE
Added a general idea of function to refactor array from Column letters to Column numbers before sort. You need to update to make some checks whether your column letters cover couple of rows (e.g. "A:B", instead of "A:A") or whether if you have columns further than "ZZ:ZZ".

How from Columns separated dataset, to a comma separated one?

i need to separate the columns of my dataset into comma separated how con I do this? I need a dataset that looks like this:
#VBasic2008 here is what i get in the middle of the sheet: the first and second row are my tries with your function CONCAT. While i need something like the rightest part of the image.... like 6,40,45,52. Not all the values merged..
So i did it using CONCAT function but i had to manually compute that for each column i show how for the ones that eventually will need help (note i used ; instead of , beacause my excel seems not working with ,)
and this is finally the final output
Ok but what if I have a dataset of 1000 columns? This process need to be much much quicker than this. This is not optimized.
I have written several comments on your question which may be hard to follow. So I decided to make a full solution which actually a trick.
Note that Microsoft Excel tries to guess the data structure of the file content if the file is suffixed with .csv (extension). For that reason, whenever you open a .csv file, you get your data in columns instead of a single columns with comma separated values.
In order to achieve what you want, first, save your data as in the comma separated values (.csv) file format.
Then change your file extension from .csv to, i.e. .txt (text file) for example:
if your file name is "data.csv", change it to "data.txt". Please make sure you see the file extension as csv before you change it because in some case you don't see the file extension; therefore when you rename it, it remains a csv file.
Note: If you don't see file extension, if you are on Microsoft Windows, follow this link.
Once you rename the file into txt file format, you can then open it in your Excel application by going to File -> Open -> then browse the txt file.
There you go and get what you one.
You don't need to code or use any functions to achieve that although you can choose to do so if you wish as it is also a good solution.
If you are looking for a formula solution
TEXTJOIN(", ", TRUE, Range)
where Range is the column span of expected values
Option Explicit
Sub CSV()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LR As Long, xRow As Range
LR = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
For Each xRow In ws.Range("A1:A" & LR)
xRow.Offset(0, 6).Value = WorksheetFunction.TextJoin(", ", True, xRow.Resize(1, 6))
Next xRow
Application.ScreenUpdating = True
End Sub
This is already separated by commas, so you just have to rename it to a .csv file.
in Windows Explorer, go to the ribbon and go to the 'view' tab and enable 'File Name Extensions'.
Navigate to your file, right click and rename it to THEFILENAME.csv instead of THEFILENAME.xlsx
Now when you open this up in excel, it should have the grid.
What is the extension of the file? .xls, .txt or .csv?
If it is in .xls then you can simply open the file in Excel and then use the File->save as menu and then selecting the Comma Separated from the file type drop down.
If file has .csv extension and you are trying to open it in Excel then you will see columns even the file has commas in it. To verify that if the file is comma separated then simply open with notepad or other text editors to see the comma separated values.
If there is any other separator like colon : or other and want to replace with comma then simply use the find and replace option in notepad.
CONCAT Excel UDF
I wrote this a while ago.
In VBE add a module and copy the following code to it.
The Code
'*******************************************************************************
' Purpose: Concatenates the values of cells of a specified range.
' Read only. String.
' Syntax: CONCAT(Range, Separator, Row0Column1)
' Inputs:
' Range A valid range in any open workbook. Required.
' Separator A string to be used as a separator between the values.
' Default is the space character. Optional.
' Row0Column1 If 0 it concatenates by row, if 1 then by column.
' Default is 0. Optional.
' Returns: A string containing all the values of the specified range.
'*******************************************************************************
Function CONCAT(ByVal Range As Range, Optional Separator As String = _
" ", Optional Row0Column1 As Long = 0) As String
'***************************************
' Variables
Dim xdRowStart As Long, xdRowEnd As Long, xdRowCounter As Long
Dim xdColumnStart As Long, xdColumnEnd As Long, _
xdColumnCounter As Long
Dim xdSep As String, xdString As String, xdCheckEmptyString As String
Dim xdWS As Worksheet
'***************************************
' Values
xdString = ""
xdSep = Separator
Set xdWS = Range.Worksheet
xdRowStart = Range.Row
xdRowEnd = xdRowStart + Range.Rows.count - 1
xdColumnStart = Range.Column
xdColumnEnd = xdColumnStart + Range.Columns.count - 1
'***************************************
' Determine concatenated direction: by row or by column
Select Case Row0Column1
Case 0
GoTo ConcatenateByRow
Case 1
GoTo ConcatenateByColumn
Case Else
MsgBox "Row0Column1:" & vbCr _
& "Ommit or use 0 for Concatenating by Row." & vbCr _
& "Use 1 for Concatenating by Column."
GoTo ConcatenateFinal
End Select
'***************************************
' Concatenate by Row:
ConcatenateByRow:
For xdRowCounter = xdRowStart To xdRowEnd
For xdColumnCounter = xdColumnStart To xdColumnEnd
If xdString = "" Then 'xdString is empty; all cells were empty so far
xdCheckEmptyString = xdWS.Cells(xdRowCounter, xdColumnCounter)
If xdCheckEmptyString <> "" Then 'Cell is not empty
xdString = xdCheckEmptyString
End If
Else 'xdString is not empty
xdCheckEmptyString = xdWS.Cells(xdRowCounter, xdColumnCounter)
If xdCheckEmptyString <> "" Then 'Cell is not empty
xdString = xdString & xdSep & xdCheckEmptyString
End If
End If
Next xdColumnCounter
Next xdRowCounter
GoTo ConcatenateFinal
'***************************************
' Concatenate by Column:
ConcatenateByColumn:
For xdColumnCounter = xdColumnStart To xdColumnEnd
For xdRowCounter = xdRowStart To xdRowEnd
If xdString = "" Then 'xdString is empty; all cells were empty so far
xdCheckEmptyString = xdWS.Cells(xdRowCounter, xdColumnCounter)
If xdCheckEmptyString <> "" Then 'Cell is not empty
xdString = xdCheckEmptyString
End If
Else 'xdString is not empty
xdCheckEmptyString = xdWS.Cells(xdRowCounter, xdColumnCounter)
If xdCheckEmptyString <> "" Then 'Cell is not empty
xdString = xdString & xdSep & xdCheckEmptyString
End If
End If
Next xdRowCounter
Next xdColumnCounter
GoTo ConcatenateFinal
'***************************************
ConcatenateFinal:
CONCAT = xdString
End Function
'*******************************************************************************
Usage in Excel
=CONCAT($A1:$G1,",") and copy down:
=CONCAT($A2:$G2,",")

excel vba: using string to set slicer doesn't work

I'm trying to set the slicer for a pivot table based on values I collected earlier in a string.
The code below works:
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = Array( _
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]")
However, instead of having two values like J17 and J18, I could have an unknown amount of them. So the code could also be:
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = Array( _
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]", "[dXref].[Merk].&[J50]", "[dXref].[Merk].&[J500]")
To solve this, in earlier code I collect whatever values I want to filter and I put them together in a string called "txt".
So the string "txt" could contain this:
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]"
or
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]", "[dXref].[Merk].&[J50]", "[dXref].[Merk].&[J500]"
Then I assumed this would work:
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = Array( _
txt)
I thought that replacing the code that normally works to set the slicer with a variable containing the same code would work. However I keep getting error messages that give a clue that there is something wrong with the comma in the txt string when setting the slicer.
I have been searching online for hours and trying endless things. I might be missing something simple.... can someone figure this out? Thanks a lot.
The full sub below (which is now working):
Sub FiltersMatchen()
Dim Selectie As Range
Dim FilterArray() As String
Dim FilterString As String
Dim i As Long
Dim Merk As Range
Dim FiltercodeBegin As String
Dim FiltercodeEinde As String
Set Selectie = Selection
i = 0
ReDim FilterArray(0)
For Each Merk In Selectie
FilterArray(i) = Merk
i = i + 1
ReDim Preserve FilterArray(i)
Next
FiltercodeBegin = "[dXref].[Merk].&["
FiltercodeEinde = "]"
For i = LBound(FilterArray) To UBound(FilterArray) - 1
FilterString = FilterString & FiltercodeBegin & FilterArray(i) & FiltercodeEinde & Chr(44)
Next i
FilterString = Left(FilterString, Len(FilterString) - 1)
FilterArray = Split(FilterString, ",")
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = FilterArray
End Sub
The answer is that I had to split the string into an array, and the individual items in the array don't need to have the " " characters around them while preparing those items. I assumed they were required because if you manually fill in the array (what you see when you record the a macro) they are there.
So, manually an array item looks like this:
"[dXref].[Merk].&[J17]"
Using an array, an item looks like this:
[dXref].[Merk].&[J17
I edited the start post with the solution. The sub is used to apply a selection of the pivot table to the slicer connected to that pivot table.

Trouble converting Excel file to .csv

My customer has a file they have used, for some time, to upload data to their application. The field in the Oracle table is VARCHAR 50. The field in the Excel spreadsheet they use is column width 50 and marked as General. I change it to Text and save as .csv. All the rows that have alphanumeric in the field save fine, but the ones that are all numbers convert to scientific notation. I found something on here changing the format (Data > Text to columns) from General to Text. Nothing makes the numbers convert as text like the other values in the field in this spreadsheet. What can I do to ensure it does this every time? They say it is the 1st time they've seen it... I doubt that. Still, I am on the hook to solve the problem. I need to provide them with a solution so that when they send me this data, twice a year, to upload, it works correctly. Any help would be greatly appreciated. Thanx.
Public Sub WritetxtFiles()
Const DELIMITER As String = ","
Dim myRecord As Range
Dim myField As Range
Dim nFileNum As Long
Dim sOut As String
Dim counter As Long
Dim holder As String
Dim theDate As Date
Dim formattedDate As String
Dim dailyDirectory As String
nFileNum = FreeFile
theDate = Now
formattedDate = Format(theDate, "yyyyMMdd")
dailyDirectory = "C:\TEMP\" + formattedDate
If Dir(dailyDirectory, vbDirectory) = vbNullString Then
MkDir (dailyDirectory)
Else
End If
Sheets("orig.txt").Activate ' Adjust to match your sheet name
Open dailyDirectory & "\orig.txt" For Output As #nFileNum ' Adjust to match your desired output
counter = 1
For Each myRecord In Range("A1:A" & Range("A" & Rows.Count).End(xlUp).Row)
If Cells(counter, 1) <> "" Then
With myRecord
For Each myField In Range("A" & counter, "F" & counter)
sOut = sOut & DELIMITER & myField.Text
Next myField
Print #nFileNum, Mid(sOut, 2)
sOut = Empty
End With
Else
End If
counter = counter + 1
Next myRecord
Close #nFileNum
end sub
This will create a comma delimited file in your C:\Temp[yyyymmdd]
Well, this is for a gov't customer and they don't allow macros in their Excel files. I was able to save as a 97-2003 workbook, then save as .csv. If I open with Notepad instead of Excel, the .csv file appears correct. If I open it with Excel, it converts. Go figure. Thanx for the help. Wish I could have used it.

Resources