Function deletes lines it shouldn't - excel

When I execute this it will delete the "Refined" lines and when I comment this function out it the "Refined" lines don't get deleted. I inherited this code and I have added every section to has "Refined" because I'm attempting to add extra products besides "gas" and "oil" but I really don't know VBA or programming. I've just been winging it and it's mostly worked except this section.
My question is what's wrong with what I added to the code? I edited or added every line that has the word "refined" in it. It works as intended for oil and gas but will always delete the refined column. When it executes data for oil, gas, and refined populates the worksheet but it will instantly delete all the refined columns that it pulled in.
I don't have the proficient to rewrite it as a different do until loop without some sort of code template.
This function checks the Current Prices tab for any columns that are duplicates of the day before or weekends and deletes the column
Function PricesCleanup() As Boolean
Dim r, c As Integer
Dim removeCount As Integer
Dim removeColumn As Boolean
Dim isGas, isOil, isRefined As Boolean
c = FIRSTDATA_COL
removeCount = 0
Do Until IsEmpty(ws_currentprices.Cells(COMMODITY_ROW, c)) 'check every col of prices
'Start at the row of the first date and reset remove flag
r = FIRSTDATE_ROW
removeColumn = True
'Check each column, at least until there is a discrepancy between prices so we know it's not a holiday
Do Until ((r > 12 And IsEmpty(ws_currentprices.Cells(r, c))) Or r > 60 Or Not removeColumn)
'If the prices don't match, we know it's not a holiday
If (ws_currentprices.Cells(r, c) <> ws_currentprices.Cells(r, c + 1)) Then
'If the first row is empty or matches second row, it's likely due to near EoM index shifting and requires special handling
If r = FIRSTDATE_ROW Then
If IsEmpty(ws_currentprices.Cells(r, c)) Then
'Oil index swap
removeColumn = False
End If
If (ws_currentprices.Cells(r, c) = ws_currentprices.Cells(r + 1, c) And ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Gas") Then
'Gas index swap so clear cell and allow to continue but only if within the last few workdays of the month
If (DateDiff("d", WorksheetFunction.WorkDay(ws_currentprices.Cells(r, BUCKET_COL), -1), ws_currentprices.Cells(ASOFDATE_ROW, c)) > -3) Then
ws_currentprices.Cells(r, c).ClearContents
End If
End If
Else
'Not index related and no match, so don't remove column
removeColumn = False
End If
End If
r = r + 1
Loop
'Check for weekend dates or dates from prior month
If Weekday(ws_currentprices.Cells(ASOFDATE_ROW, c)) = 1 Or Weekday(ws_currentprices.Cells(ASOFDATE_ROW, c)) = 7 Or Month(ws_currentprices.Cells(ASOFDATE_ROW, c)) <> Month(ws_currentprices.Cells(ASOFDATE_ROW, BUCKET_COL)) Then
removeColumn = True
End If
'Remove column if flagged
If removeColumn Then
removeCount = removeCount + 1
ws_currentprices.Columns(c).EntireColumn.Delete
c = c - 1
End If
'Copy up spot price
If Not IsEmpty(ws_currentprices.Cells(FIRSTDATE_ROW, c)) Then
ws_currentprices.Cells(SPOT_ROW, c) = ws_currentprices.Cells(FIRSTDATE_ROW, c)
ElseIf Not IsEmpty(ws_currentprices.Cells(FIRSTDATE_ROW + 1, c)) Then
ws_currentprices.Cells(SPOT_ROW, c) = ws_currentprices.Cells(FIRSTDATE_ROW + 1, c)
Else
ws_currentprices.Cells(SPOT_ROW, c) = ""
End If
c = c + 1
Loop
'Check if any columns are left and return bool value
isGas = False
isOil = False
isRefined = False
c = FIRSTDATA_COL
Do Until IsEmpty(ws_currentprices.Cells(COMMODITY_ROW, c))
If (ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Gas") Then
isGas = True
ElseIf (ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Oil") Then
isOil = True
ElseIf (ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Refined") Then
isRefined = True
End If
c = c + 1
Loop
If (isGas And isOil And isRefined) Then
PricesCleanup = True
Else
PricesCleanup = False
End If
End Function

Related

How to lookup multiple cells based on multiple criteria in VBA

I'm extremely new to VBA and have tried Googling to find what I need, but have fallen short.
I have a sheet (Sheet1) containing a list of companies that currently have, or at some point have had, a subscription. The list contains the City (Col A), the Company (Col B), the Category (Col C) and a Cancellation Date (Col D) (if applicable). What I want to do is fill in the current company for that city/category on a different sheet. I want those headers to be City (Col D), Category 1 (Col E), Category 2 (Col F), and Category 3 (Col G).
Here are images of the two sheets of test data:
Sheet 1
Sheet 2
There can only be one company per category per city. For example: in my test data, company D was under Category 1 in San Antonio, but cancelled on 11/12/2021. Then, company N took that spot in San Antonio. So, in my table on Sheet 2, I want company N to be populated. The data set I'm using this for is very large and constantly changing, so I would like an automated way to do this.
Here is a copy of the code I pieced together:
Sub CompanyLookup()
With Application
.Calculation = xlCalculationManual
.EnableEvents = False
.ScreenUpdating = False
End With
Dim lastRowInCity, lastRowOutCity, i, k, m As Long
Dim lookFor, j, inArray, outArray, findArray As Variant
Dim inWks, outWks As Worksheet
Set inWks = ThisWorkbook.Sheets(1)
Set outWks = ThisWorkbook.Sheets(2)
lastRowInCity = inWks.Cells(Rows.Count, "A").End(xlUp).Row
lastRowOutCity = outWks.Cells(Rows.Count, "D").End(xlUp).Row
lastRowCategory = inWks.Cells(Rows.Count, "C").End(xlUp).Row
lastRowDate = inWks.Cells(Rows.Count, "D").End(xlUp).Row
lastColCategory = outWks.Cells(Columns.Count, "D").End(xlToLeft).Column
inArray = Range(inWks.Cells(1, 1), inWks.Cells(lastRowInCity, 3))
findArray = Range(outWks.Cells(1, 4), outWks.Cells(lastRowOutCity, 4))
outArray = Range(outWks.Cells(1, 5), outWks.Cells(lastRowOutCity, 5))
On Error Resume Next
For i = 2 To lastRowOutCity
For j = 2 To lastRowInCity
For k = 2 To lastRowCategory
For m = 2 To lastRowDate
lookFor = findArray(i, 1)
If inArray(j, 1) = lookFor And inArray(m, 4) < 1 And inArray(k, 3) = outArray(lastColCategory, 1) Then
outArray(i, 1) = inArray(j, 2)
Exit For
End If
Next j
Next m
Next k
Next i
Range(outWks.Cells(1, 5), outWks.Cells(lastRowOutCity, 5)) = outArray
With Application
.Calculation = xlCalculationAutomatic
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
Assuming your data looks exactly as your screenshots:
Sub CompanyLookup()
Dim sourceData, resultData, rngSource As Range, rngResult As Range
Dim r As Long, c As Long, city As String, cat As String, rSrc As Long
Set rngSource = ThisWorkbook.Sheets(1).Range("A1").CurrentRegion
Set rngResult = ThisWorkbook.Sheets(2).Range("D1").CurrentRegion
sourceData = rngSource.Value
resultData = rngResult.Value
'scan through the results array
For r = 2 To UBound(resultData, 1)
city = resultData(r, 1) 'city
For c = 2 To UBound(resultData, 2)
cat = resultData(1, c) 'category
'Scan the source data for a city+category match,
' ignoring lines with a cancellation date
For rSrc = 2 To UBound(sourceData, 1)
If Len(sourceData(rSrc, 4)) = 0 Then 'no cancellation date
If sourceData(rSrc, 1) = city And sourceData(rSrc, 3) = cat Then
resultData(r, c) = sourceData(rSrc, 2) 'populate the company
Exit For 'done searching
End If
End If
Next rSrc
Next c
Next r
rngResult.Value = resultData 'populate the results
End Sub
I had exact same issue this week, and from what i read online, the fact that you cannot use vlookup or find function for multiple criteria. Mostly people prefer using .find fuction and when you find it, you can use loop to find second criteria. It was what i used.

How to get small value in specific range

I want to get 1st,2nd,3rd,...nth...small values in dates which are on column D. but there was a specific category which is shown in column E. I wrote a code to get a specific range call p. and it is working. that means when category C it selects only C values in the range. when it is equal F it gets only F values.
Now I want to get a row number of 1st small value. but category C it gives correct small value. but it becomes category F it again gave the previous results. can anyone help me with this problem.?
dim p as range, c as range, i as integer, irow as long
dim ary(1 to 5) as varient
ary(1) = "C"
ary(2) = "F"
ary(3) = "B"
ary(4) = "PC"
ary(5) = "BC"
For i = 1 To UBound(ary)
cat = ary(i)
Set p = Nothing
Set c = Nothing
For Each c In Range("E: E")
If c.Value = cat Then
If p Is Nothing Then
Set p = c.Offset()
Else
Set p = Union(p, c)
End If
End If
Next c
irow = Application.WorksheetFunction.Match(WorksheetFunction.Small(p.Offset(, -1), 1), Range("D:D"), 0)
Cells(4, 12) = Cells(irow, 5)
next i

Why does this vba macro ignores the value after an if else?

I have two columns, the first one is a date with Year/Month format and the other a numerical value of an evaluation that i have done. I want to get the average value for each month with a macro( i need to do it so many times an a lot of data on it). So, i decided to create an array of dates and a Matrix of evaluation results. The goal is to group all numeric values by date and get the average per month. The problem is that this code ignores the value when the actual and last cells are different.
Dim i As Integer 'number of rows
Dim J As Integer 'manage row change
Dim G As Integer 'manage column change
Dim Fecha(48) As String
Dim Matriz_FI(100, 100) As Double
'-------------------------------------------------------------- --
J = 0
G = 0
For i = 2 To 10
If i = 2 Then
Matriz_FI(J, G) = Sheets("Nueva Database").Cells(i, 11).Value
Fecha(J) = Sheets("Nueva Database").Cells(i, 3).Value
G = G + 1
Else
If (Sheets("Nueva Database").Cells(i, 3).Value = Sheets("NuevaDatabase").Cells(i - 1, 3).Value) Then
'Column change in Matriz_FI
Matriz_FI(J, G) = Sheets("Nueva Database").Cells(i, 11).Value
G = G + 1
MsgBox ("Same")
Else
'Row change in Matriz_FI
J = J + 1
Fecha(J) = Sheets("Nueva Database").Cells(i, 3)
G = 0
Matriz_FI(J, G) = Sheets("Nueva Database").Cells(i, 11).Value
MsgBox ("Different")
End If
End If
Next
End Sub

How to clear Textbox if case not found?

I scan a barcode into an ActiveX textbox. It selects the relevant case and performs the calculation/event depending on the barcode. Every code is connected to an event.
One out of 100+ scans is not correctly decoded to the computer. As such, it does not match a case and does not make the textbox value "". It then appends to every other scan entering into the textbox. Aka "15 - FT - R" might scan in as "15 - FT -R".
I need the code to recognize this as a non case and delete it.
Since the barcode scans each character one at a time, nothing is equal to a case until the barcode value has completely entered the textbox.
Is there any way to tell if the barcode info is done being scanned?
My biggest challenge is how to stop the rest of the text from entering the box once it does not match a case.
My next biggest challenge is setting variables.
Private Sub TextBox1_Change()
Dim ws As Worksheet, v, e, f, g, k, i4
Set ws = Worksheets("Sheet1")
v = TextBox1.Value
e = 0
f = 0
g = 0
k = 0
i4 = 0
Select Case v
Case "15 - FT - R": f = 5
e = 11
k = 2
g = "15 - FT - R"
Case "150 - FT - C": f = 30
e = 11
k = 2
g = "150 - FT - C"
Case "R Waste": f = 4
e = 9
k = 2
g = "R Waste"
Case "C Waste": f = 4
e = 10
k = 2
g = "C Waste"
Case "Accident - 4": k = 5
'other cases here....
End Select
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'g = name of the item being used for the time stamp
'k = Case Selection
'i4 = Count for Cutting Station 1 timestamp, row reference
If k = 2 Then
'Coating Station
'accidental scan references for coating
ws.Cells(4, 4) = f
ws.Cells(5, 4) = e
ws.Cells(f, e) = ws.Cells(f, e) + 1
'adds master roll
i4 = ws.Cells(4, 30)
'count function
Cells(i4, 25).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i4, 26).Value = g
'formatting timestamp
TextBox1.Activate
TextBox1.Value = ""
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'k = Case Selection
'i4 = Count for Cutting Station 1 timestamp, row reference
ElseIf k = 5 Then
'Accidental scan
f = ws.Cells(4, 4)
e = ws.Cells(5, 4)
ws.Cells(f, e) = ws.Cells(f, e) - 1
i4 = ws.Cells(4, 30)
'count function
Cells(i4, 25).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i4, 26).Value = "Accident"
'formatting timestamp
TextBox1.Activate
TextBox1.Value = ""
End If
End Sub
Set TextBox properties:
EnterKeyBehavior TRUE
Multiline TRUE
Use this in your VBA _Change call back:
If Not Right(Me.Scan.Value, 1) = vbLf Then Exit Sub
In essence, we're now just looking for the LF character after enabling the multiline capability of the textbox.

How to remove part of the array?

The program I am working on involves reading and determining the difference between i - (i+1) and i-(i-1) from excel.
If the difference exceeds 4 then the program deletes the row at i.
The program works well at the first try. Suddenly, it says that "You can not change part of an Array".
Option Explicit
Sub Data_Delet()
Dim a As Double, b As Double, c As Double, i As Double
Dim rkill As Range
' a,b, and c are used as steps in order to proceed to the next data points
a = 18
b = 0
c = 0
With ThisWorkbook.Worksheets("Sheet1")
' The second do loop delete data points that does not follow the requirements
Do
If Abs(.Cells(a - 1, 2) - .Cells(a, 2)) > 4 And Abs(.Cells(a, 2) - .Cells(a + 1, 2)) > 4 Then
If rkill Is Nothing Then
Set rkill = Rows(a)
Else
Set rkill = Union(rkill, Rows(a))
End If
End If
a = a + 1
Loop Until .Cells(a, 2).Value = ""
If Not rkill Is Nothing Then rkill.EntireRow.Delete
' The third Do loop determines the number of data points that are still present after deleting the data points
Do
i = .Cells(17 + c, 1)
c = c + 1
Loop Until .Cells(17 + c, 1).Value = ""
' The if statment determine whether or not the number data points from before are the same after deletion process
If b = c Then
.Cells(2, 5) = "N"
Else
.Cells(2, 5) = "Y"
End If
' c is the number of data point after deletion
.Cells(12, 5) = c
End With
End Sub
The error "You cannot change part of an array" on rkill.EntireRow.Delete means that the row you want to delete is intersecting a range referenced in an array formula (a formula with braces).
Excel does not allow this. One way would be to remove the offending array formula(s) at the start of your code, and redefine it/them again at the end of your code. Or find a solution to turn these array formulas into normal formulas.

Resources