I was wondering if there was a way to tell excel not to display some variables if the VLookup function couldn't find anything.
Here's roughly what my code does: take some numbers in another excel workbook by looking them up, compare that value from the previous year and take the difference, display that difference in another spreadsheet, all in one big merged cell.
Some excerpts from my code:
cashO = Val(Application.VLookup("cash" & "*", Workbooks("creditreport.csv").ActiveSheet.Range("A1:F199"), 4, False))
Then the difference cash = Round(cashN - cashO, 0)
Then the Display: MergedCell.Value = "Cash increased by" & cash
But I dont want to display cash if it couldnt find cash in the first place (if this is the case, cash = 0 both when cash couldnt be found and when the change is null).
I was thinking of creating an array with all my variables (cash, ...) and then loop through it. But I couldn't find anything online on "if not found dont display anything".
Best,
You can use an if else statement to check the value of cash and write the value if cash has a value and some other message like "no change" or "no previous value" if that's the case.
if cash = 0
MergedCell.Value = "No Change"
Else
MergedCell.Value = "Cash increased by" & cash
End If
Or you could just check if the function returns an error:
if iserror(Application.VLookup("cash" & "*", Workbooks("creditreport.csv").ActiveSheet.Range("A1:F199"), 4, False)) then
cash = 0
else
cashO = Val(iserror(Application.VLookup("cash" & "*", Workbooks("creditreport.csv").ActiveSheet.Range("A1:F199"), 4, False))
....other statements for whatever...
end if
I hope I understood you, that you mean that VLookup didn't find a match for "cash" , if that's the case you need error-handling.
If that's the case, try the code below:
Sub VLookup_Test()
On Error Resume Next
cashO = Val(Application.VLookup("cash" & "*", Workbooks("creditreport.csv").ActiveSheet.Range("A1:F199"), 4, False))
If Err.Number <> 0 Then
MsgBox "cashO not found" '
' Do your actions if cashO not found with VLookup
End If
On Error GoTo 0
End Sub
Related
I'm kind of new to Access VBA and I’m having issues with my loop.
I have reviewed various books, websites, asked various friends. Currently I’m trying to have a user input two characters, and then if the two characters equal a certain combination then it is supposed to equal a numeric value, and then use the value in a distance calculation.
The user inputed values are strings and everything else is declared as double.
I have 200+ combinations that I am testing and have tried case statements, DLookup, do while, do until, if, and elseif loops with no success.
I'm also limited by IT and I’m unable to use DAO code.
Any assistance would be greatly appreciated.
I would first suggest creating a table to formally define the various character combinations and the corresponding value for each combination. This has the advantage that the combinations may be easily maintained going forward, rather than defining such combinations as part of queries or in VBA code.
Such a table could be as simple as containing three fields:
Character 1 (Text)
Character 2 (Text)
Value (Number)
You could then populate such a table with your valid combinations:
With the combinations rigorously defined, you have many options regarding how to prompt the user to enter the two characters and obtain the correponding value.
A very simplistic approach might be to use a form with three textboxes:
Here, the first two textboxes would be unbound, and might be called char1 and char2, and the third textbox might be called result and have a Control Source property equal to:
=DLookup("Value", "LookupTable", "char1 = '" & [char1] & "' and char2 = '" & [char2] & "'")
This would yield the following behaviour:
Consider using Access as a database and GUI application by storing your 200+ combinations in a table with corresponding numeric value. Then have an SQL query filter by user input and use resulting value for needed calculations. Below requires creating and using four Access objects: table, query, form, and module.
Table (tblCombinations)
id combn1 combn2 numeric_value
1 A B 150
2 C D 225
3 E F 100
4 G H 75
5 I J 200
...
SQL (no loops needed; using Access form control values)
SELECT c.combn1, c.combn2, c.numeric_value
FROM tblCombinations c
WHERE c.combn1 = Forms!myForm!myUserInputField1
AND c.combn2 = Forms!myForm!myUserInputField2
And even pass needed numeric value in distance calculation formula which can be a VBA function in a standard module:
SELECT c.combn1, c.combn2, Distance_Calculation(c.numeric_value) As distance_result
FROM tblCombinations c
WHERE c.combn1 = Forms!myForm!myUserInputField1
AND c.combn2 = Forms!myForm!myUserInputField2
VBA (place in standard module)
Public Function Distance_Calculation(num_value As Long) As Double
...
Distance_Calculation = some_value
End Function
You can use following type function in your result form button or after event on both textboxes-
Dim resultValue as Integer
If DCount("numeric_value", "tblCombinations", "[combn1] = '" & Forms!myForm!myUserInputField1 & "' and [combn2] = '" & Forms!myForm!myUserInputField2 & "'") > 0 then
resultValue = Dlookup("numeric_value", "tblCombinations", "[combn1] = '" & Forms!myForm!myUserInputField1 & "' and [combn2] = '" & Forms!myForm!myUserInputField2 & "'")
txtResult = Distance_Calculation(resultValue)
Else
Msgbox "No such combination exist. Kindly check combimation", vbinformation, "Information"
txtResult = 0
End if
I've been searching for a way to fill in column 'H' and 'I' of the attached image.
For 'H' I need to count every time the date and date shipped out don't equal for each item. It will be something like this:
(A:A <> D:D, B:B = $G$2, E:E <> "Base Inventory")
The second equation is to calculate the average lead time for each item:
Average(E:E - D:D) where B:B = $G$2, and D:D = "Complete" while ignoring rows with blanks
The table is much larger than the image and I can't use a helper row.
Thanks.
Example Sheet
For the first part, shipping calc, I wrote a function that will compute it for you:
Public Function Shippingcalc(item1 As Range, codes As Range, date2 As Range, shipped As Range, status As Range)
Dim Count As Integer
Count = 0
For n = 1 To codes.Rows.Count
If status.Cells(n, 1).Value <> "Base Inventory" Then
If codes.Cells(n, 1).Value = item1.Cells(1, 1).Value Then
If shipped.Cells(n, 1).Value <> 0 Then
If shipped.Cells(n, 1).Value <> date2.Cells(n, 1).Value Then
Count = Count + 1
End If
End If
End If
End If
Next n
Shippingcalc = Count
End Function
You have to implement that as a macro and macro-enable the workbook.
Then the function in H would look something like:
=Shippingcalc(G2, B$2:B$10, A$2:A$10, D$2:D$10, C$2:C$10)
And you can copy that (of course updating to the full column size).
Something similar should work for the other computation.
For some reason this morning while I was taking a poop, the equation for lead time came to me. It was way simpler than I imagined and goes back to high school math.
Average = (SUM(Received date) - SUM(Shipped date)) / Total
=(SUMIFS(E:E,B:B, G2,D:D,"<>",E:E,"<>") - SUMIFS(D:D,B:B, G2,D:D,"<>",E:E,"<>")) / (COUNTIFS(B:B, Q14, D:D,"<>",E:E,"<>")+1)
Thanks for your help guys.
I need to summarize unique values from a row into a column that's in the same row. My goal is in the second row of the attached image where T:Z contains the data and AA:AC contains the summary (I typed the values in for the demo). The first row is what is currently occurring where I tried using a nested if function for values greater than zero, but I also tried using an index match function to no avail. The issue is I either receive duplicates in AA:AC or not all values are included.
Currently using Excel 2016
So if I understand you correctly, you are going to have a sheet of rows of data. You want to look in the columns T:Z and then generate a list of unique values (non-zero) in the columns AA:AC. I assume that you know you will never have more than 3 unique values, but I can't be sure that this wasn't just an omission.
Either way, the below code should work:
Sub Find_Uniques()
Dim X As Integer, Y As Integer, Z As Integer
Dim Temp_Strings() As String
For X = 1 to 10000 'This assumes you don't have more than 10,000 rows of data
ReDim Temp_Strings(1 to 5) As String
For Y = 20 to 26
If Range(Cells(X,Y).Address).Value <> "" And Range(Cells(X,Y).Address).Value <> 0 Then
For Z = 1 to 5
If Temp_Strings(Z) = "" Then
Temp_Strings(Z) = Range(Cells(X,Y).Address).Value
Exit For
End If
If Temp_Strings(Z) = Range(Cells(X,Y).Address).Value Then Exit For
Next Z
End If
Next Y
For Z = 1 to 5
If Temp_Strings(Z) <> "" Then Range(Cells(X,Z+26).Address)).Value = Temp_String(Z)
Next Z
Next X
End Sub
Thank you all for your help. Instead of extracting the data from the row, I wrote a macro that changed the zeros to blanks, deleted the blank cells, and shifted them to the left. After that it was easy to cut the range and paste it into the old data set to be analyzed.
Sub clean_data()
Sheets("Reason data").Range("H:Z").Replace 0, ""
Call delete_blanks
End Sub
Sub delete_blanks()
Sheets("Reason data").Range("H:Z").SpecialCells(xlCellTypeBlanks).Delete (xlToLeft)
Call move_data
End Sub
Sub move_data()
'Copies reason data and pastes it into data worksheet
Sheets("Reason data").Range("A3:K3", Sheets("Reason data").Range("A3:F3").End(xlDown)).Cut _
Sheets("Data").Range("A1").End(xlDown).Offset(1)
End Sub
I want a user to be able to search for a specific term and if it is in the database a message will be given saying that it is in the database.
This is the code that I have made so far and it runs without errors, but when I enter a search term it always says "We are sorry, but that does not seem to be in our system" and it always says this 3 times. I am using Pycharm as my IDE, but I don't think that this should make a difference.
I am semi new to Python so please be patient with me if I have missed something simple : )
import csv
uIn = input("Please enter a search term: ")
with open('database.csv', 'r') as uFile:
fileReader = csv.reader(uFile, delimiter=',')
for row in fileReader:
if uIn == row[1]: #True
print (uIn + "is in file")
else: #False
print("We are sorry, but that does not seem to be in our system")
----------------------------------------------------------Edit----------------------------------------------------------------
Thank you, #Rahul Bhatnagar, for your answer; it showed me that I needed to switch == with in.
This does answer part of the question, and I have figured out some of the other part, the else statement prints for every row that does not have the uIn inside of it. So say the uIn was on the third row the script would print the #False statement twice and the #True statement once. This is alrightish, but if the uIn is on say the 50th row or the 100th row then there would be 49 or 99 #false statements printed.
I would now say that about 50% of my problem is fixed, the part that is not fixed, is to only print 1 #true or 1 #false statement if it is in the file.
import csv
def search(uIn):
found = false;
with open('database.csv', 'r') as uFile:
fileReader = csv.reader(uFile, delimiter=',')
for row in fileReader:
if uIn in row: #True
found = true;
if(found):
print ("Found the string in file!")
else:
print("We are sorry, but that does not seem to be in our system")
uIn = raw_input("ST: ")
search(uIn)
Where my database.csv file is :
search,terms,go,into,this,file,in,this,format
You're trying to find uIn at position 1 of row in all cases, which is not going to be the situation.
Going through a tutorial but I cannot figure out how to do this. It wants me to have the program display all 10 names previously entered after the quit sub. I've experimented with some stuff but cannot figure out how to do this.
'ARRAYS.BAS
'List handling with arrays
dim names$(10) 'set up our array to contain 10 items
[askForName] 'ask for a name
input "Please give me your name ?"; yourName$
if yourName$ = "" then print "No name entered." : goto [quit]
index = 0
[insertLoop]
'check to see if index points to an unused item in the array
if names$(index) = "" then names$(index) = yourName$ : goto [nameAdded]
index = index + 1 'add 1 to index
if index < 10 then [insertLoop] 'loop back until we have counted to 10
'There weren't any available slots, inform user
print "All ten name slots already used!"
goto [quit]
[nameAdded] 'Notify the name add was successful
print yourName$; " has been added to the list."
goto [askForName]
[quit]
end
Insert this code between [quit] and end:
for I = 0 TO 10
print names$(I)
next I
That'll work ;)