ColumnsExample
I'm trying to compare four columns for information. First Matching Location 1 data to Location 2 data, then comparing the Rented out Columns.
If Location 2 Rented Out Column D (for a specific car that matches column A with Column C) is greater than Rented out Column B then highlight cell (column D) yellow. Also if Rented out Column D
An example pic (ColumnsExample above) would be Honda and Dodge Rented out Column D would be highlighted for failing this.
I'm assuming I'll have to assign Daily, Weekly and Monthly a number value to compare against. Just not sure where to start!
Dim Alert As Range
Dim Daily, Weekly, Monthly As Integer
Set Daily = 1
Set Weekly = 2
Set Monthly = 3
Set ws = ActiveSheet
Set w = ws.Rows(1).Find("Rented Out 2", lookat:=xlWhole)
If Not w Is Nothing Then
For Each Alert In ws.Range(w, ws.Cells(Rows.Count,
w.Column).End(xlUp)).Cells
If Alert <= "Daily" Then
'Not sure how I can set this condition based on matching
'Location 1 with location 2 as well as Rented1 out vs
'Rented out 2
Alert.Interior.Color = 65535
End If
Next Alert
End If
Use a Dictionary for the comparison and a Function for the converting the strings to numbers.
Option Explicit
Sub MyMacro()
Dim ws As Worksheet, iLastRow As Long, r As Long
Dim dict As Object, key As String, s As String
Dim i As Integer
Set dict = CreateObject("Scripting.Dictionary")
Set ws = ActiveSheet
' scan col A & B
iLastRow = ws.Cells(Rows.Count, "A").End(xlUp).Row
For r = 2 To iLastRow
key = Trim(ws.Cells(r, "A"))
If Len(key) > 0 Then
s = Trim(ws.Cells(r, "B"))
i = TextToNo(s) ' convert text to number
If i = 0 Then
MsgBox "ERROR col B = '" & s & "'", vbCritical, "Row = " & r
Exit Sub
End If
' add to dictionery
If dict.exists(key) Then
MsgBox "ERROR col A duplicate key = '" & key & "'", vbCritical, "Row = " & r
Exit Sub
Else
dict.Add key, i
End If
End If
Next
' scan col C & D
iLastRow = ws.Cells(Rows.Count, "C").End(xlUp).Row
For r = 2 To iLastRow
key = Trim(ws.Cells(r, "C"))
If Len(key) > 0 Then
If dict.exists(key) Then
s = Trim(ws.Cells(r, "D"))
i = TextToNo(s)
If i = 0 Then
MsgBox "ERROR col D = '" & s & "'", vbCritical, "Row = " & r
Exit Sub
End If
' compare col D with col B
If i > dict(key) Then
ws.Cells(r, "D").Interior.Color = vbYellow
Else
ws.Cells(r, "D").Interior.Color = vbWhite
End If
End If
End If
Next
MsgBox "Finished"
End Sub
Function TextToNo(s As String) As Integer
Select Case LCase(s)
Case "daily": TextToNo = 1
Case "weekly": TextToNo = 2
Case "monthly": TextToNo = 3
Case Else: TextToNo = 0
End Select
End Function
Related
I have been asked to remake the excel workbook to index where we keep the items.
I have an excel sheet with a table ( excel table) that contains the information.
If the there the value in column 6 ="10" then that means the item is in box 10.
then I need to get the right shelve, this is found by the numbers in column 7 (shelve) and 8 (rack). subsequently the information about the item has to be put in another sheet which gives a visual representation of the box.
I am struggling to get the desired result, does anyone have some suggestions?
Sub box()
Dim rng As Range
For x = 1 To 12
Set rng = Sheets("Register").ListObject("Table1").Range(x, 8).Value
If Range("Table1").ListObject.Range(x, 6).Value = "10" Then
If Range("Table1").ListObject.Range(x, 7).Value = "1" Then
Sheets("box 10").Range(3, rng).Value = Range("Table1").ListObject.Range(x, 2).Value & Range("Table1").ListObject.Range(x, 3)
End If
End If
Next x
End Sub
Please, try the next code. It will iterate in the table DataBodyRange and build a sheet name obtained by concatenation of "Box " with value in table column 6 (in your workbook). If such a sheet does not exist, a warning message is sent and stops the code:
Option Explicit
Sub box()
Dim boxVal As String, tbl As ListObject, shBox As Worksheet, rngRef As Range, x As Long
Dim shelvNo As Long, rackNo As Long
Dim iRow As Long: iRow = 1 ' row where "rack" exist
Dim iCol As Long: iCol = 1 'column letter where "rack" exists (C:C)
Set tbl = Sheets("Register").ListObjects("Table1")
For x = 1 To tbl.DataBodyRange.Rows.Count 'on the frist row there are ABC, ABC etc.
If tbl.DataBodyRange.Cells(x, 1) = "" Then Exit For
boxVal = tbl.DataBodyRange.Cells(x, 6).Value
On Error Resume Next
Set shBox = Sheets("Box " & boxVal) 'set the sheet of the appropriate box 'set the sheet of the appropriate box
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
MsgBox "No sheet named """ & "box " & tbl.DataBodyRange.Cells(x, 6).Value & """ exists" & vbCrLf & _
"Please, create it and run the code again!": Exit Sub
End If
On Error GoTo 0
Set rngRef = shBox.Cells(iRow, iCol)
shelvNo = iRow + 1 + tbl.DataBodyRange.Cells(x, 7).Value
rackNo = iCol + tbl.DataBodyRange.Cells(x, 8).Value - 1
rngRef.Offset(shelvNo, rackNo).Value = tbl.DataBodyRange.Cells(x, 2).Value & " " & tbl.DataBodyRange.Cells(x, 3).Value
Next x
MsgBox "Ready..."
End Sub
I have an excel file contains 20 columns and 100 rows, If the Value in A2= Reportable certain columns in excel are mandatory and similarly if A2 =Non-Reportable then certain other column values are mandatory, So need an VB script to check this condition if any of the mandatory column cell value is blank then on save of excel file throw an error message and error message should list all the missing column headers and rows. The script should validate all the rows, tried the below code, but not working and also i get mutiple error message instead of single error message
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim Cell As Range
Dim flag As Boolean
flag = False
If Cells(1, 1) = "" Then flag = True
For Each Cell In Range("B2:B3")
If Cell = "" Then
MsgBox ("Signoff is missing")
flag = True
Exit For
End If
Next Cell
For Each Cell In Range("D2:D3")
If Cell = "" Then
MsgBox ("tax Regime value is missing")
flag = True
Exit For
End If
Next Cell
For Each Cell In Range("E2:E3")
If Cell = "" Then
MsgBox ("Classification value is missing")
flag = True
Exit For
End If
Next Cell
Cancel = flag
End Sub
update - added error.txt as output
update2 - colour cells red and create error sheet
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim ws As Worksheet, lastrow As Long, ar(2)
Dim msg As String, c As String
Dim r As Long, i As Long, n As Long
ar(1) = Array("B", "D", "F") ' non-reportable columns
ar(2) = Array("C", "E", "G") ' reportable columns
Set ws = ActiveSheet
With ws
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For r = 2 To lastrow
.Rows(r).Cells.Interior.Pattern = xlNone
n = 0
If LCase(.Cells(r, "A")) = "non-reportable" Then
n = 1
ElseIf LCase(.Cells(r, "A")) = "reportable" Then
n = 2
End If
If n > 0 Then
For i = 0 To UBound(ar(n))
c = ar(n)(i)
If .Cells(r, c) = "" Then
.Cells(r, c).Interior.Color = RGB(255, 0, 0) ' red
msg = msg & vbLf & "Row " & r & " missing " & .Cells(1, c)
End If
Next
End If
Next
End With
Dim wsErr As Worksheet, arErr
If Len(msg) > 0 Then
' create error sheet
arErr = Split(msg, vbLf)
Set wsErr = Sheets.Add(after:=Sheets(Sheets.Count))
wsErr.Name = "Errors " & Format(Now(), "yyyy-mm-dd hhmmss")
wsErr.Cells(1, 1).Resize(UBound(arErr) + 1) = Application.Transpose(arErr)
Open "errors.txt" For Output As #1
Print #1, msg
Close #1
MsgBox "Missing data see error.txt", vbCritical
Cancel = True
Else
MsgBox "All good"
End If
End Sub
I am basically stuck in this VBA as I did not know how to lookup 2 cells and return with another cell value. It might be solve with reading project name to lookup first and then reading the week number to match and return the phase in grey area, but to get the 2 lookup together is difficult for me.
This is the first sheet where the input come in as week number and date in each phase
The second sheet will search the project number and week number, return the phase in column J and next.
Use a couple of Dictionary Objects as look-ups to the Project rows and Week columns.
Option Explicit
Sub Macro()
Const SHT_PRJ = "Project"
Const COL_ID_PRJ = "E"
Const COL_PH1 = "F" ' Phase 1
Const ROW_HDR_PRJ = 2 ' header
Const SHT_DEM = "Demand"
Const COL_ID_DEM = "D"
Const ROW_HDR_DEM = 1
Const MAX_PH = 6 ' phases 1 to 6
Dim wb As Workbook
Dim wsIn As Worksheet, wsOut As Worksheet
Dim cell As Range, rng As Range
Dim iRow As Long, iLastRow As Long, iCol() As Integer, iLastCol As Integer
Dim iColWk As Integer
Dim iColor As Variant, sWk As String, iPh As Integer
Set wb = ThisWorkbook
Set wsIn = wb.Sheets(SHT_PRJ)
Dim dict As Object, dictWk As Object, key
Set dict = CreateObject("Scripting.Dictionary")
Set dictWk = CreateObject("Scripting.Dictionary")
' build lookup to row for ID
iLastRow = wsIn.Cells(Rows.Count, COL_ID_PRJ).End(xlUp).Row
For iRow = ROW_HDR_PRJ + 1 To iLastRow
key = Trim(wsIn.Cells(iRow, COL_ID_PRJ))
If dict.exists(key) Then
MsgBox "Duplicate key " & key, vbCritical, "Row " & iRow
Exit Sub
ElseIf Len(key) > 0 Then
dict.Add key, iRow
End If
Next
' build look up to column for week
Set wsOut = wb.Sheets(SHT_DEM)
iLastCol = wsOut.Cells(ROW_HDR_DEM, Columns.Count).End(xlToLeft).Column
For Each cell In wsOut.Cells(ROW_HDR_DEM, 1).Resize(1, iLastCol)
key = Trim(cell.Value)
If dictWk.exists(key) Then
MsgBox "Duplicate week " & key, vbCritical, "Col " & cell.Column
Exit Sub
ElseIf Len(key) > 0 Then
dictWk.Add key, cell.Column
End If
Next
' update demand sheet
ReDim iCol(MAX_PH)
iLastRow = wsOut.Cells(Rows.Count, COL_ID_DEM).End(xlUp).Row
For Each cell In wsOut.Cells(ROW_HDR_DEM + 1, COL_ID_DEM).Resize(iLastRow)
iColor = cell.Interior.ColorIndex
key = Trim(cell.Value)
' each project
If Len(key) > 0 And iColor <> xlColorIndexNone Then '-4142
iRow = dict(key) ' row on project sheet
If iRow < 1 Then
MsgBox "ID " & key & " not found", vbCritical, _
wsOut.Name & " Row " & cell.Row
Exit Sub
Else
' get week numbers for each phase
For iPh = 1 To MAX_PH
sWk = wsIn.Cells(iRow, COL_PH1).Offset(0, 2 * (iPh - 1))
If Len(sWk) > 0 Then
' look up week to column
iCol(iPh) = dictWk(sWk)
If iCol(iPh) < 1 Then
MsgBox "Week " & sWk & " not found", vbCritical, _
wsOut.Name & " Row " & cell.Row
Exit Sub
Else
' update sheet
wsOut.Cells(cell.Row, iCol(iPh)) = "Phase " & iPh
End If
End If
Next
' fill in gaps with previous
For iColWk = iCol(1) To iCol(MAX_PH)
Set rng = wsOut.Cells(cell.Row, iColWk)
If rng.Value = "" Then
rng.Value = rng.Offset(0, -1).Value
End If
Next
End If
End If
Next
MsgBox dict.Count & " projects processed"
End Sub
I want to compare 2 excels files [Having only 1 sheet in both] having 10-15 columns and rows will be more than 30K. We got one excel macro file which complete the comparison within 5-10Mins. Limitation of this macro is that it can compare only 2-3 columns at a time. So every time we need to run this macro multiple times which is time consuming process. So I created one utility file [.vbs file] which perform this task in one go but it takes around 1-3Hrs.
Is there any other way to perform this comparison in short time in one go?
startTime=Timer()
Set objExcel=Createobject("Excel.application")
objExcel.Visible=True
Set objWorkbook=objExcel.Workbooks.Open("E:\QTP trial version\Data.xls")
'Set deleteAnalysis_CopySheet=objWorkbook.sheets("Analysis_Copy")
'deleteAnalysis_CopySheet.delete
'Set deleteSummarySheet=objWorkbook.sheets("Summary")
'deleteSummarySheet.delete
Set objAnalysis_Copy=objWorkbook.sheets.add
objAnalysis_Copy.name="Analysis_Copy"
Set objSummary=objWorkbook.sheets.add
objSummary.name="Summary"
objSummary.Cells(1,1)="Analysis Row Count"
objSummary.Cells(2,1)="Reporting Row Count"
objSummary.Cells(3,1)="Analysis Column Count"
objSummary.Cells(4,1)="Reporting Column Count"
objSummary.Cells(5,1)="Difference of Row Count"
objSummary.Cells(6,1)="Difference of Column Count"
objSummary.Cells(7,1)="False Count"
' ------------------------1st Check - Verify the position of ''Metrics' in Analysis and Reporting tab. It must be same---------------------
'Get the control of Analysis tab
Set objAnalysis=objExcel.Worksheets.Item("Analysis")
intAnalysisRowCount=objAnalysis.Usedrange.rows.count
objSummary.Cells(1,2)=intAnalysisRowCount
intAnalysisColCount=objAnalysis.Usedrange.Columns.count
objSummary.Cells(3,2)=intAnalysisColCount
'Get Column number of 'Metric' Column from Analysis tab
For intMetricAnalysis=1 to intAnalysisColCount
If(Trim(Lcase(objAnalysis.Cells(1,intMetricAnalysis)))=Trim(Lcase("Metrics"))) Then
Exit for
End If
Next
'Get all Analysis columns in 1 string
strAnalysisColumnOrder=""
For intAnalysisColumnOrder=1 to intAnalysisColCount
strAnalysisColumnOrder=strAnalysisColumnOrder&"*"&objAnalysis.Cells(1,intAnalysisColumnOrder)
If(intAnalysisColumnOrder=1) then
strAnalysisColumnOrder=Replace(strAnalysisColumnOrder,"*","")
End If
Next
Set objReporting=objExcel.Worksheets.Item("Reporting")
intReportingRowCount=objReporting.Usedrange.rows.count
objSummary.Cells(2,2)=intReportingRowCount
intReportingColCount=objReporting.Usedrange.Columns.count
objSummary.Cells(4,2)=intReportingColCount
''Get Column number of 'Metric' Column from Reporting tab
For intMetricReporting=1 to intReportingColCount
If(Trim(Lcase(objReporting.Cells(1,intMetricReporting)))=Trim(Lcase("Metrics"))) Then
Exit for
End If
Next
'Get all Reporting columns in 1 string
strReportingColumnOrder=""
For intReportingColumnOrder=1 to intAnalysisColCount
strReportingColumnOrder=strReportingColumnOrder&"*"&objReporting.Cells(1,intReportingColumnOrder)
If(intReportingColumnOrder=1) then
strReportingColumnOrder=Replace(strReportingColumnOrder,"*","")
End If
Next
''Metric' column number must be same
If(intMetricAnalysis<>intMetricReporting) then
msgbox "Merics column is at "&intMetricAnalysis&" position in 'Analysis' Tab And at "&intMetricReporting&" position in 'Reporting' tab. 'Metrics' column should be at same position in both tab."
strMetricsFlag=False
Else
strMetricsFlag=True
End IF
'-----------2nd Check, Verify count of columns in 'Analysis' And 'Reporting' tab . It Must be same
If intAnalysisColCount<>intReportingColCount Then
msgbox "Column count of 'Reporting' Tab is not same as of 'Analysis tab'."
strAnalysisColCount=False
Else
strAnalysisColCount=True
End If
''---------------3rd Check , Verify Order of columns in 'Analysis' And 'Reporting' tab . It Must be same
If Trim(Lcase(strAnalysisColumnOrder))<>Trim(Lcase(strReportingColumnOrder)) then
msgbox "Column order of 'Reporting' Tab is not same as of 'Analysis tab'. Reporting column order should be "&strAnalysisColumnOrder
strAnalysisColumnOrderFlag=False
Else
strAnalysisColumnOrderFlag=True
End IF
'Creare 'Analysis_Copy' tab and add headers
Set objAnalysisCopy=objExcel.Worksheets.Item("Analysis_Copy")
strFirstCoulmn_AggKeys=""
For intHeaderAggkey=1 to intMetricAnalysis-1
strFirstCoulmn_AggKeys=strFirstCoulmn_AggKeys&"*"&objAnalysis.Cells(1,intHeaderAggkey)
If(intHeaderAggkey=1) then
strFirstCoulmn_AggKeys=Replace(strFirstCoulmn_AggKeys,"*","")
End If
Next
objAnalysisCopy.Cells(1,1)=strFirstCoulmn_AggKeys
strSecondCoulmn_AnalysisMetrics=""
For intHeaderAnalysisMetrics=intMetricAnalysis+1 to intAnalysisColCount
strSecondCoulmn_AnalysisMetrics=strSecondCoulmn_AnalysisMetrics&"*"&objAnalysis.Cells(1,intHeaderAnalysisMetrics)
If(intHeaderAnalysisMetrics=intMetricAnalysis+1 ) then
strSecondCoulmn_AnalysisMetrics=Replace(strSecondCoulmn_AnalysisMetrics,"*","")
End If
Next
objAnalysisCopy.Cells(1,2)="Analysis_"&strSecondCoulmn_AnalysisMetrics
objAnalysisCopy.Cells(1,3)="Reporting_"&strSecondCoulmn_AnalysisMetrics
objAnalysisCopy.Cells(1,4)="Status"
objWorkbook.Save
'$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
If strAnalysisColumnOrderFlag=False OR strMetricsFlag=False OR strAnalysisColCount=False Then
msgbox "So Data Comparision can not be done"
objWorkbook.Save
objWorkbook.Close
objExcel.Quit
Else
intFalseCount=0
For intAnalysisRow=2 to intAnalysisRowCount
' ------ Get the control of ''Analysis' tab and the string of Aggrecate Keys [strAnalysisAggrData] and respective metrics [strAnalysisMetricsData]
Set objAnalysis=objExcel.Worksheets.Item("Analysis")
' Append all data of each row which is before 'Metrics' column
strAnalysisAggrData=""
For intAnalysisColumn=1 to intMetricAnalysis-1
strAnalysisAggrData=strAnalysisAggrData&"*"&objAnalysis.Cells(intAnalysisRow,intAnalysisColumn)
If(intAnalysisColumn=1) then
strAnalysisAggrData=Replace(strAnalysisAggrData,"*","")
End If
Next
' ' Append all data of each row which is after 'Metrics' column
strAnalysisMetricsData=""
For intFromMetric=intMetricAnalysis+1 to intAnalysisColCount
strAnalysisMetricsData=strAnalysisMetricsData&"*"&objAnalysis.Cells(intAnalysisRow,intFromMetric)
If(intFromMetric=intMetricAnalysis+1 ) then
strAnalysisMetricsData=Replace(strAnalysisMetricsData,"*","")
End If
Next
' ------ Get the control of ''Reporting' tab and the string of Aggrecate Keys [strAnalysisAggrData] and respective metrics [strAnalysisMetricsData]
Set objReporting=objExcel.Worksheets.Item("Reporting")
For intReportingRow=1 to intReportingRowCount
' Append all data of each row which is before 'Metrics' column
strReportingAggrData=""
For intBeforeMetricReporting=1 to intMetricReporting-1
strReportingAggrData=strReportingAggrData&"*"&objReporting.Cells(intReportingRow,intBeforeMetricReporting)
If(intBeforeMetricReporting=1) then
strReportingAggrData=Replace(strReportingAggrData,"*","")
End If
Next
' Append all data of each row which is after 'Metrics' column
strReportingMetricsData=""
For intFromReportingMetric=intMetricReporting+1 to intReportingColCount
strReportingMetricsData=strReportingMetricsData&"*"&objReporting.Cells(intReportingRow,intFromReportingMetric)
If(intFromReportingMetric=intMetricReporting+1 ) then
strReportingMetricsData=Replace(strReportingMetricsData,"*","")
End If
Next
'------------------------------------------------------------ Actual Comparision will be from here ------------------------------------------
If Trim(LCase(strAnalysisAggrData))=Trim(LCase(strReportingAggrData)) Then
objAnalysisCopy.Cells(intAnalysisRow,1)=strAnalysisAggrData
objAnalysisCopy.Cells(intAnalysisRow,2)=strAnalysisMetricsData
objAnalysisCopy.Cells(intAnalysisRow,3)=strReportingMetricsData
'Compare Metrics Data
If Trim(LCase(strAnalysisMetricsData))=Trim(LCase(strReportingMetricsData)) Then
objAnalysisCopy.Cells(intAnalysisRow,4)="PASS"
objAnalysisCopy.Cells(intAnalysisRow,4).font.color=vbGreen
Else
objAnalysisCopy.Cells(intAnalysisRow,4)="FAIL"
intFalseCount=intFalseCount+1
objAnalysisCopy.Cells(intAnalysisRow,4).font.color=vbRed
End If
Exit For
End If
Next
Next
objSummary.Cells(5,2)=intAnalysisRowCount-intReportingRowCount
objSummary.Cells(6,2)=intAnalysisColCount-intReportingColCount
objSummary.Cells(7,2)=intFalseCount
objSummary.Cells(7,2).font.color=vbRed
objWorkbook.Save
objWorkbook.Close
objExcel.Quit
EndTime=Timer()
TotalTime=EndTime-startTime
msgbox "Data Comparision is Completed. Comparision time is "&TotalTime&"Secs"
End If
Use a dictionary and you avoid the nested loops and only scan each sheet once. For example as a VBA macro (untested)
Sub compare()
Dim wb As Workbook
Dim ws(2) As Worksheet, wsSum As Worksheet, wsCopy As Worksheet
Dim rowCount(2) As Long, colCount(2) As Integer, colMetric(2) As Integer
Dim colsMetric(2) As String, colsAll(2) As String, colsKeys(2) As String
Dim bMetricsFlag As Boolean, bColCountFlag As Boolean, bColOrderFlag As Boolean
Dim i As Long, ar, msg As String, intFalseCount As Long
Dim t0 as Single
t0 = Timer
Set wb = ThisWorkbook
Set ws(1) = wb.Sheets("Analysis")
Set ws(2) = wb.Sheets("Reporting")
Set wsSum = wb.Sheets("Summary")
wsSum.Cells.Clear
wsSum.Range("A1:A7") = WorksheetFunction.Transpose(Array("Analysis Row Count", _
"Reporting Row Count", "Analysis Column Count", "Reporting Column Count", _
"Difference of Row Count", "Difference of Column Count", "False Count"))
Set wsCopy = wb.Sheets("Analysis_Copy")
wsCopy.Cells.Clear
' get stats for each sheet 1-Analyis 2=Reporting
For i = 1 To 2
ar = Stats(ws(i))
rowCount(i) = ar(0)
colCount(i) = ar(1)
colMetric(i) = ar(2)
colsAll(i) = ar(3)
colsMetric(i) = ar(4)
colsKeys(i) = ar(5)
Next
' summary
With wsSum
.Cells(1, 2) = rowCount(1)
.Cells(2, 2) = rowCount(2)
.Cells(3, 2) = colCount(1)
.Cells(4, 2) = colCount(2)
End With
' check stats
'Metric' column number must be same
If colMetric(1) = 0 Or colMetric(2) = 0 Or colMetric(1) <> colMetric(2) Then
msg = "Metrics columns not the same or missing : " & vbCr & _
"Analysis : " & colMetric(1) & vbCr & _
"Reporting : " & colMetric(2)
MsgBox msg, vbCritical
bMetricsFlag = False
Else
bMetricsFlag = True
End If
' Verify count of columns
If colCount(1) <> colCount(2) Then
msg = "Column counts not the same : " & vbCr & _
"Analysis : " & colCount(1) & vbCr & _
"Reporting : " & colCount(2)
MsgBox msg, vbCritical
bColCountFlag = False
Else
bColCountFlag = True
End If
'Verify Order of columns
If colsAll(1) <> colsAll(2) Then
msg = "Column order not the same : " & vbCr & _
"Analysis : " & colsAll(1) & vbCr & _
"Reporting : " & colsAll(2)
MsgBox msg, vbCritical
bColOrderFlag = False
Else
bColOrderFlag = True
End If
With wsCopy
.Cells(1, 1) = colsKeys(1)
.Cells(1, 2) = "Analysis_" & colsMetric(1)
.Cells(1, 3) = "Reporting_" & colsMetric(2)
.Cells(1, 4) = "Status"
End With
' checks OK ?
If bColOrderFlag And bMetricsFlag And bColCountFlag Then
' ok
Else
MsgBox "So Data Comparision can not be done", vbCritical
Exit Sub
End If
' start comparison
Dim dict As Object, m As Long, c As Long, s As String
Dim sKey As String, sMetric As String
Set dict = CreateObject("Scripting.Dictionary")
' scan Reporting sheet to build dictionary
m = colMetric(2)
For i = 1 To rowCount(2)
'join cols up to and after metric col
sMetric = "": sKey = ""
For c = 1 To colCount(2)
s = Trim(ws(2).Cells(i, c))
If c < m Then
If sMetric <> "" Then sMetric = sMetric & "*"
sMetric = sMetric & s
ElseIf c > m Then
If sKey <> "" Then sKey = sKey & "*"
sKey = sKey & s
End If
Next
dict(sKey) = sMetric
Next
' scan Analysis sheet to compare dictionary
m = colMetric(1)
For i = 2 To rowCount(1)
'join cols up to and after metric col
sMetric = "": sKey = ""
For c = 1 To colCount(1)
s = Trim(ws(1).Cells(i, c))
If c < m Then
If sMetric <> "" Then sMetric = sMetric & "*"
sMetric = sMetric & s
ElseIf c > m Then
If sKey <> "" Then sKey = sKey & "*"
sKey = sKey & s
End If
Next
' result
wsCopy.Cells(i, 1) = sKey
wsCopy.Cells(i, 2) = sMetric
wsCopy.Cells(i, 3) = dict(sKey)
' pass or fail
If sMetric = dict(sKey) Then
wsCopy.Cells(i, 4) = "PASS"
wsCopy.Cells(i, 4).Font.Color = vbGreen
Else
wsCopy.Cells(i, 4) = "FAIL"
wsCopy.Cells(i, 4).Font.Color = vbRed
intFalseCount = intFalseCount + 1
End If
Next
With wsSum
.Cells(5, 2) = rowCount(1) - rowCount(2)
.Cells(6, 2) = colCount(1) - colCount(2)
.Cells(7, 2) = intFalseCount
.Cells(7, 2).Font.Color = vbRed
End With
MsgBox i - 2 & " rows scanned " & vbCrLf & _
intFalseCount & " FAILED", vbInformation, Int(Timer - t0) & "seconds"
End Sub
Function Stats(ws As Worksheet) As Variant
Dim c As Integer, ar(5) As Variant, s As String
ar(0) = ws.UsedRange.Rows.Count
ar(1) = ws.UsedRange.Columns.Count
ar(2) = 0 'metric column
ar(3) = "" ' col aggregated
ar(4) = "" ' cols upto not including metric
ar(5) = "" ' cols after metric
For c = 1 To ar(1)
s = LCase(Trim(ws.Cells(1, c)))
If s = "metric" Then
ar(2) = c
End If
' aggregate headers before/after metric
If ar(2) = 0 Then
If ar(4) <> "" Then ar(4) = ar(4) & "*"
ar(4) = ar(4) & s
ElseIf c > ar(2) Then
If ar(5) <> "" Then ar(5) = ar(5) & "*"
ar(5) = ar(5) & s
End If
' aggregate all
If ar(3) <> "" Then ar(3) = ar(3) & "*"
ar(3) = ar(3) & s
Next
Stats = ar
End Function
Test data generator
Sub testdata()
Dim ws As Worksheet, n, r, c, ar
ar = Array("", "Analysis", "Reporting")
For n = 1 To 2
Set ws = Sheets(ar(n))
For r = 1 To 30000
For c = 1 To 15
ws.Cells(r, c) = Chr(64 + c) & r & "_abcdefghijklmnopqrstuvwxyz_"
Next
Next
ws.Cells(1, 10) = "metric" ' col J
Next
MsgBox "test data created"
End Sub
Get the row # of cell that matches with search "string" in particular column without loop - Column has multiple matches"
I want to get the row # of matched string in particular column without looping because i have more than 50000 records and I don't want to loop each row to find out
Sub Mismatch()
Dim sht As Worksheet
Set Sht5 = ThisWorkbook.Worksheets("Result")
Dim FindString As String
FindString = "FAIL"
Sht5.Activate
Columncount = Sht5.Range(Cells(1, 1), Cells(1, 1000)).Cells.SpecialCells(xlCellTypeConstants).Count 'CODE NEED TO BE UPDATED WITH COLUMN LENGTH
'To find the column count
lastReportRow = Sht5.Range("B" & Rows.Count).End(xlUp).row
'to find the last used row
For i = 2 To Columncount + 1
Set Valuefound = Sht5.Range(Cells(2, i), Cells(lastReportRow, i)).Find(FindString, After:=Range("B2"), LookIn:=xlValues)
If Valuefound Is Nothing Then
MsgBox "Value not found"
Else
For r = 2 To lastReportRow
ActualString = Sht5.Cells(r, i).Value
If FindString = ActualString Then
MsgBox r
Else
End If
'For x = 2 To lastReportRow
Next
End If
Next
End Sub
You can use Match:
'...
lastReportRow = Sht5.Range("B" & Rows.Count).End(xlUp).row
For i = 2 To Columncount + 1
Set rng = Sht5.Range(Sht5.Cells(2, i), Sht5.Cells(lastReportRow, i))
Do
m = Application.Match(FindString, rng, 0)
If IsError(m) Then Exit Do '<< not found: exit search for this column
Debug.Print "Found '" & FindString & "' at " & rng.Cells(m).Address
'reset search range
Set rng = Sht5.Range(rng.Cells(m+1), Sht5.Cells(lastReportRow, i))
Loop
Next i
End Sub
See in your code you can replace:
This:
For i = 2 To Columncount + 1
Set Valuefound = Sht5.Range(Cells(2, i), Cells(lastReportRow,
i)).Find(FindString, After:=Range("B2"), LookIn:=xlValues)
If Valuefound Is Nothing Then
MsgBox "Value not found"
Else
For r = 2 To lastReportRow
ActualString = Sht5.Cells(r, i).Value
If FindString = ActualString Then
MsgBox r
Else
End If
'For x = 2 To lastReportRow
Next
End If
Next
With This:
Set Valuefound = sht5.UsedRange.Find(FindString, After:=Range("B2"), LookIn:=xlValues, lookat:=xlWhole)
If Valuefound Is Nothing Then
MsgBox "Value not found"
Else
MsgBox Valuefound.Row
End If
Valuefound.row will give you the exact row. Also you can add Valuefound.column to get the column number of the Valuefound
Also, you can add Range.FindNext as per this link to access the values that occur more than once in the data.