Hi Allen,
I would agree with your approach, using IIf() function. It is better
than my solution. It would be nice if the other functions would deal with
nulls. And it would be nice if Microsoft would both add the Nz function
to
the Jet and ACE engines and fix it so that it deals with the types
correctly.
Or provide an enhanced version so as not cause potential problems with
existing usages.
However, your item b struck me as maybe not being quite correct. I
did
know about Nz() not being known to Jet. But it seemed to me that Jet did
know about other functions. So I went to your web site that you listed
(below) to see what your thoughts were. I learned some new stuff there!
However, on it you stated that a number of functions (IsNull(), DLookup(),
DSum(), etc.) are not known to Jet and therefore cause it to call out to
VBA.
Again, that did not quite seem to match up with my memory. But my memory
could be faulty. So I decided to do some testing. At first I tried the
testing from within Access 2007, but that did not really give me a
definitive
answer. So I decided to shift to using C# to do the testing. That way,
there should not be any doubt. It would succeed if Jet or ACE knew about
the
function. It would fail if they do not.
Here is the code I used (somewhat scrunched to be readable in the
newsgroup window):
-------------------------------------------------
private void btnTestJetACE_Click(object sender, EventArgs e)
{
ADODB.Connection cnnAccessDB = new ADODB.Connection();
ADODB.Recordset rstTest = new ADODB.Recordset();
int intProviderIndex;
int intFunctionIndex;
String strResults = String.Empty;
String [] strarrFunctions =
{"CBool(5)",
"CByte(1)",
"CCur(\"123.12\")",
"CDate(\"12/31/2008\")",
"CDbl(\"123.456\")",
"CDec(\"543.2101234\")",
"CDec(\"543.2101234\", 3)",
"CInt(\"123\")",
"CSng(\"321.21\")",
"CStr(123)",
"DLookUp(\"[Last Name]\", \"[tblSome Table]\", " +
"\"ID = 4\")",
"DMax(\"ID\", \"[tblSome Table]\")",
"DSum(\"IND_Curr\", \"[tblSome Table]\")",
"IIf(True, \"ABC\", 123)",
"IsNull(Null)",
"Nz(Null, \"123\")"};
String [] strarrProviders =
{"Microsoft.Jet.OLEDB.4.0",
"Microsoft.ACE.OLEDB.12.0"};
for (intProviderIndex = 0; intProviderIndex <=
strarrProviders.GetUpperBound(0);
intProviderIndex++)
{
if (strResults != String.Empty)
strResults += "\r\n\r\n" +
"==============================\r\n\r\n";
strResults += "Provider: " +
strarrProviders[intProviderIndex];
cnnAccessDB.Open("Provider=" +
strarrProviders[intProviderIndex] +
";Data Source=D:\\ProgSrcs\\Access\\Database1.mdb",
String.Empty, String.Empty, 0);
for (intFunctionIndex = 0; intFunctionIndex <=
strarrFunctions.GetUpperBound(0);
intFunctionIndex++)
{
strResults += "\r\n\r\n" +
strarrFunctions[intFunctionIndex] + ":\r\n\t";
try
{
rstTest.Open("select " +
strarrFunctions[intFunctionIndex], cnnAccessDB,
ADODB.CursorTypeEnum.adOpenStatic,
ADODB.LockTypeEnum.adLockReadOnly,
(int) ADODB.CommandTypeEnum.adCmdText);
strResults += "Succeeded: " +
rstTest.Fields[0].Value.ToString();
rstTest.Close();
}
catch (Exception excpt)
{
strResults += "Failed: " + excpt.Message;
}
}
cnnAccessDB.Close();
}
txtResults.Text = strResults;
}
-------------------------------------------------
And here are the results that I got:
-------------------------------------------------
Provider: Microsoft.Jet.OLEDB.4.0
CBool(5):
Succeeded: -1
CByte(1):
Succeeded: 1
CCur("123.12"):
Succeeded: 123.12
CDate("12/31/2008"):
Succeeded: 12/31/2008 12:00:00 AM
CDbl("123.456"):
Succeeded: 123.456
CDec("543.2101234"):
Failed: Wrong number of arguments used with function in query expression
'CDec("543.2101234")'.
CDec("543.2101234", 3):
Succeeded: 0
CInt("123"):
Succeeded: 123
CSng("321.21"):
Succeeded: 321.209991455078
CStr(123):
Succeeded: 123
DLookUp("[Last Name]", "[tblSome Table]", "ID = 4"):
Succeeded: Smith
DMax("ID", "[tblSome Table]"):
Succeeded: 5
DSum("IND_Curr", "[tblSome Table]"):
Succeeded: 5300089.64
IIf(True, "ABC", 123):
Succeeded: ABC
IsNull(Null):
Succeeded: -1
Nz(Null, "123"):
Failed: Undefined function 'Nz' in expression.
==============================
Provider: Microsoft.ACE.OLEDB.12.0
CBool(5):
Succeeded: -1
CByte(1):
Succeeded: 1
CCur("123.12"):
Succeeded: 123.12
CDate("12/31/2008"):
Succeeded: 12/31/2008 12:00:00 AM
CDbl("123.456"):
Succeeded: 123.456
CDec("543.2101234"):
Failed: Wrong number of arguments used with function in query expression
'CDec("543.2101234"'.
CDec("543.2101234", 3):
Succeeded: 0
CInt("123"):
Succeeded: 123
CSng("321.21"):
Succeeded: 321.209991455078
CStr(123):
Succeeded: 123
DLookUp("[Last Name]", "[tblSome Table]", "ID = 4"):
Succeeded: Smith
DMax("ID", "[tblSome Table]"):
Succeeded: 5
DSum("IND_Curr", "[tblSome Table]"):
Succeeded: 5300089.64
IIf(True, "ABC", 123):
Succeeded: ABC
IsNull(Null):
Succeeded: -1
Nz(Null, "123"):
Failed: Undefined function 'Nz' in expression.
-------------------------------------------------
So, Jet and ACE know about all of those functions, except, as
expected,
for the Nz() function. One interesting oddity was the CDec() function.
In
VBA it uses just one parameter. Jet and ACE both expect two parameters.
But
both return zero to the input I provided when I gave it two parameters.
Not
certain why. A bug? Or just ignorance of what that second parameter
should
be? Anyway, just thought you would want to know.
Sincerely,
Clifford Bass
Allen Browne said:
Ray, here's another approach. Instead of using Nz() wrapped in CDate(),
try:
IIf([dbEnrollment].[End_Date] Is Null, [qmaxattendance].[maxofdate],
[dbEnrollment].[End_Date])
Advantages:
a) IIf() does not mess up the data types.
b) JET knows how to execute the IIf(), so it avoids 2 VBA function calls.
c) Still works even if maxofdate is null (which would cause CDate() to
fail.)
For more explanation of this opinion, see:
Common query hurdles - IIf(), not Nz()
at:
http://allenbrowne.com/QueryPerfIssue.html#Nz