Calling an Access VBA function with IF statement as an argument - vba

Assuming I have the following MS Access 2016 function:
Public Function TestFunction(ByVal strTest As String) As String
Is there a way to call the function with something similar to:
strReturn = TestFunction(If a = 1 Then "Apple" Else "Orange")
I would like to write something as compact as possible, and avoid having to write multiple lines for the call, such as:
If a = 1 Then strArg = "Apple" Else strArg = Orange
strReturn = TestFunction(strArg)

You can accomplish this using IIf, e.g.:
strReturn = TestFunction(IIf(a=1,"Apple","Orange"))
But this is generally discouraged when working with expressions other than constants, because IIf will always evaluate both the then and else argument before returning the appropriate value depending on the outcome of the test expression, which can sometimes lead to undesired results.
For example, evaluating the following expression at the Immediate Window (Ctrl+G) will result in a division by zero error, even though the else expression will never be returned:
?iif(true,"Apple",1/0)

If the value for a comes from a well defined range then the solution would be to use either the Choose Function for a contiguous range or Switch Function for a non contiguous well defined range.
Of course the more grown up solution would be to replace both Choose or Switch with a Dictionary.

Why not something like this for multiple possibilities
Dim myArg as String
Select Case a
Case 1: myArg = "Apple"
Case 2: myArg = "Orange"
Case 3: myArg = "Pear"
'etc.
End Select
strReturn = TestFunction(myArg)

Related

How to use VBA variable for IN 'SourceDB' clause of MS-ACCESS query

I am trying to pass a vba string variable to an IN clause of a SQL statement in the query builder view.
the string is created by the following function:
Public Function GetBackEnd()
If Len(GetBackEnd) = 0 Then GetBackEnd = BackEnd
End Function
backend itself is derived from a dropdown box in userform, there are two entries in a table with two different addresses, one each for the live and developement DB's. The dropdown box sets the "environment" variable upon selection.
Property Get BackEnd() As String
Select Case Environment
Case Is = "Development"
BackEnd = DLookup("VariableValue", "Globals", "Variable= 'TestEnvironment'")
Case Else
BackEnd = DLookup("VariableValue", "Globals", "Variable= 'Backend'")
End Select
End Property
I have tried a couple of variations on the following but get an error each time.
SELECT *
FROM TableName IN 'GetBackEnd()';
I imagine its something simple but after staring at this for so long Ijust can't see it.
thank you.
Generally, you can do what you want - use a function to provide parameter strings.
Public Function GetName() As String
GetName = "foo"
End Function
SELECT * FROM bar WHERE floo = GetName()
But in some parts / cases, you can't use variables. Both IN clauses are among them.
These won't work:
GetInList = "'x', 'y', 'z'"
SELECT * FROM bar WHERE floo IN (GetInList())
and your use-case is not possible either:
GetDbPath = "C:\path\myDb.accdb"
SELECT * FROM bar IN GetDbPath()
You will have to construct the whole SQL on the fly:
Db.QueryDefs("myQuery").SQL = "SELECT * FROM TableName IN '" & GetBackEnd() & "'"
Missing WHERE clause in SQL query? Let's say
SELECT *
FROM TableName
WHERE Name = GetBackEnd;

Null Check a column value that can be Null without two DLookups?

How do I remove one DLookup from code similar to this example?
Dim sCustomerName as String
If IsNull(DLookup("sName", "tblCustomers", "iCustomerID=12345")) Then
MsgBox "Customer name is null!"
Else
sCustomerName = DLookup("sName", "tblCustomers", "iCustomerID=12345")
End If
In VBA, reading a column value that can be Null (or missing) into a variable, and then comparing it to Null gives an error. Is there a better way to do these checks?
Obviously, if there's no performance penalty, it's not bad code because of the performance hit. Is there?
Even if not, it has duplicated/copy-pasted code. How can it be rewritten to avoid this?
A Variant data type can store Null values. Try to get the value and check if Null.
Dim customerName As Variant
customerName = DLookup("sName", "tblCustomers", "iCustomerID=12345")
If Not IsNull(customerName) Then
'do stuff
End If
Another approach is the Nz() function:
You can use the Nz function to return zero, a zero-length string (" "), or another specified value when a Variant is Null.
Dim customerName As String
customerName = Nz(DLookup("sName", "tblCustomers", "iCustomerID=12345"), vbNullString)
If customerName <> vbNullString Then
'do stuff
End If

VBA Variable Scope in a Case Statement

Wondering how variables work when used in a Case statement. It seems like they are declared in the first Case, regardless of whether that Case is relevant.
'The following code will throw an error
Select Case team
Case "Philadelphia Eagles"
dim record as String
Case "Dallas Cowboys"
dim record as String
End Select
Even if 'team' isn't Philadelphia Eagles, it claims I've already declared the variable 'record'
I was under the impression that anything in a case statement was completely skipped over if that case wasn't relevant.
'The following code works
Select Case team
Case "Philadelphia Eagles"
dim record as String
Case "Dallas Cowboys"
record = "8-8"
End Select
Just want to confirm that I am understanding the Case statement correctly here.
Thank you!
Josh
Variable declarations (Dim statements) are resolved at the start of the execution of the program, which is why your Dim record statements weren't "skipped" over in your example.
You should put your variable declarations once at the top of your code, just after you start the subroutine or function. You cannot use Dim on the same variable twice. If the variable is an array which you need to resize, you can use ReDim [Preserve] instead.
Sub Subname()
Dim record as String
Select Case team
Case "Philadelphia Eagles"
record = "16-0"
Case "Dallas Cowboys"
record = "8-8"
End Select
End Sub

Is it possible to define same variable twice in classic ASP?

Is it somehow possible to declare same variable in .asp file twice? Example below does not look very clever, but this is just an example and I have to sort it out.
Dim number : number = 1
Select Case number
Case 1
Dim a
Case 2
Dim a
End Select
Theoretically you can of course declare a variable twice, the problem is, asp will throw an error, if the variable is declared in the same scope.
whatever you want to achieve, keep in mind, you can (almost) always access the variables in parent scope, thus rendering a double declaration useless.
Dim number : number = 1
Dim a
Select Case number
Case 1:
a = "whatever"
Case 2:
a = "something different"
End Select
response.write a

Pass in Array to Select Case

this may be a dense question and I'm not finding it to be a dup of this one, but I need some help with understanding if an array can be used in a Select Case statement.
I have a sub routine that I will create a string array dynamically. The XML is also listed, but it could be any of the values listed below. It will be something like this:
Dim offensiveLine() As String = New String() {"center", "right wing", "left wing"}
Dim defensiveLine As String = "defense"
Dim playerInfo = <Player><Name>John</Name><Position val="right wing"/></Player>
What I want to do is see if this player is in one of the offensiveLine. So I say:
Dim playerPosition = playerInfo.Position.#val
Select Case playerPosition
Case offensiveLine
'do something
Case defensiveLine
'do something
Case Else
'do nothing
End Select
Here is lies the issue: Case offensiveLine is invalid. I know I could write out Case "center", "right wing", "left wing", but that would defeat the purpose of what I'm trying to do, which is to make a generalized variable that is an array that can be read from in a Case statement. Secondly, I know I can't create a variable like Dim offensiveLine = ""center", "right wing", "left wing"" and pass that in.
Any insight on how I may be able to pass in an array to a Case statement and have each one evaluated?
You may want to consider using an if clause here rather than a switch. Try this logic: if offensiveLine contains playerPosition, then offensive line, etc.
You actually can use a Select statement:
Dim playerPosition = playerInfo.Position.#val
Select Case True
Case offensiveLine.Contains(playerPosition)
'do something
Case defensiveLine.Contains(playerPosition)
'do something
Case Else
'do something - otherwise you don't need the 'Case Else'
End Select
The trick is the True in the first line of the Select.
The Select..Case construct does not work like that. However, it is easy to test if an element exists in an array:
If offensiveLine.Contains(playerPosition) Then
'Do something
ElseIf defensiveLine.Contains(playerPosition) Then
'Do something else
End If