szx248
asked on
Query with VBA Function ?
I have query calls a VBA Function. And it works fine, that is from Access. But when I call this query from a VB.NET program which useds this Access Database (and has no problem running other queries) it fails on this Function saying that it does not know this function. This function does not return anything to VB.NET, it simply runs like a sp would run on SQL Server. Is this the way it is suppose to be - that VB.NET can't such queries in Access? Or is there something that I can do about this?
Which function?
ASKER
This is the fucntion:
Public Function DeliveryTotalCases(ByVal DeliveryHeaderID As Long) As Long
Dim TotalCases As Long
TotalCases = Nz(DSum("Cases", "qryDeliveryDetail_LotDeta il", "DeliveryHeaderID=" & DeliveryHeaderID), 0)
If TotalCases < 0 Then
DeliveryTotalCases = Abs(TotalCases)
ElseIf TotalCases > 0 Then
DeliveryTotalCases = TotalCases * -1
Else
DeliveryTotalCases = TotalCases
End If
End Function
I am assuming that Harfaq's answer is correct, and I was going to close this. But from your qestion it seems that there may be more to it.
Public Function DeliveryTotalCases(ByVal DeliveryHeaderID As Long) As Long
Dim TotalCases As Long
TotalCases = Nz(DSum("Cases", "qryDeliveryDetail_LotDeta
If TotalCases < 0 Then
DeliveryTotalCases = Abs(TotalCases)
ElseIf TotalCases > 0 Then
DeliveryTotalCases = TotalCases * -1
Else
DeliveryTotalCases = TotalCases
End If
End Function
I am assuming that Harfaq's answer is correct, and I was going to close this. But from your qestion it seems that there may be more to it.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Well no quite. In fact the Dsum will work (at I would infer this from your first comment). But I wanted to avoice having to run it more than once. Cause without being able to assign to var how can I do the next few lines (to change + to - and - to +) without calling this Sum() again?
Markus did nail it, because you are using a UDF.
Leaving aside the fact that Dsum() is inherantly slow and so should be avoided in queres if possible, the logic in your UDF that checks the sign of the result is...
If TotalCases < 0 Then
DeliveryTotalCases = Abs(TotalCases)
ElseIf TotalCases > 0 Then
DeliveryTotalCases = TotalCases * -1
Else
DeliveryTotalCases = TotalCases
End If
.. which translates to " if it's negative return a posive value, if it's positive return a negative value, otherwise return the value" As te "otherwize" case can only be for the value Zero, all you need to do is as harfang says, the minus sign in from of Nz does the sing conversion for you. negative turn positve an vise versa, and zero is of course not changed.
In fact your entire function could be rewritten as...
Public Function DeliveryTotalCases(ByVal DeliveryHeaderID As Long) As Long
DeliveryTotalCases= _
Nz(DSum("Cases", "qryDeliveryDetail_LotDeta il", "DeliveryHeaderID=" & DeliveryHeaderID), 0) * -1
End Function
but it would still be slow because of the use of Dsum.
If TotalCases < 0 Then
DeliveryTotalCases = Abs(TotalCases)
ElseIf TotalCases > 0 Then
DeliveryTotalCases = TotalCases * -1
Else
DeliveryTotalCases = TotalCases
End If
.. which translates to " if it's negative return a posive value, if it's positive return a negative value, otherwise return the value" As te "otherwize" case can only be for the value Zero, all you need to do is as harfang says, the minus sign in from of Nz does the sing conversion for you. negative turn positve an vise versa, and zero is of course not changed.
In fact your entire function could be rewritten as...
Public Function DeliveryTotalCases(ByVal DeliveryHeaderID As Long) As Long
DeliveryTotalCases= _
Nz(DSum("Cases", "qryDeliveryDetail_LotDeta
End Function
but it would still be slow because of the use of Dsum.
ASKER
LamberHeenan,
sorry I had overlooked Harfang's "-".
Thanks for seeting me straight.
sorry I had overlooked Harfang's "-".
Thanks for seeting me straight.
ASKER
btw, when I try using
-Nz(( Select Sum(Cases) From qryDeliveryDetail_LotDetai l Where DeliveryHeaderID= <parent table/query name>.DeliveryHeaderID), 0)
or
Select -Sum(nz(Cases,0)) From qryDeliveryDetail_LotDetai l Where DeliveryHeaderID= <parent table/query name>.DeliveryHeaderID
in the Update To row of the Update Query I get an error that says Operation must use an Updateable Query.
However this works -
DSum("-nz(Cases,0)","qryDe liveryDeta il_LotDeta il","Deliv eryHeaderI D=" & [tblDeliveryHeader].[ID])
I certainly don't prefer dsum() but why is the select not working?
-Nz(( Select Sum(Cases) From qryDeliveryDetail_LotDetai
or
Select -Sum(nz(Cases,0)) From qryDeliveryDetail_LotDetai
in the Update To row of the Update Query I get an error that says Operation must use an Updateable Query.
However this works -
DSum("-nz(Cases,0)","qryDe
I certainly don't prefer dsum() but why is the select not working?
Because the subquery (a real query in brackets) gets optimized by the engine to run much faster. This involves creating implicit relationships from the WHERE clauses, thus linking an updatable query with a non-updatable total query (the Sum()).
If you need to update (but why?), use the VB function as wrapper. Your query does not get optimized, but it remains updatable. The only other solution in Access is to use an intermediate temp table containing the sums (you can use a non-updatable query for a make table query, but not for an update query). Too much hassle here it seems.
Cheers!
(°v°)
If you need to update (but why?), use the VB function as wrapper. Your query does not get optimized, but it remains updatable. The only other solution in Access is to use an intermediate temp table containing the sums (you can use a non-updatable query for a make table query, but not for an update query). Too much hassle here it seems.
Cheers!
(°v°)
ASKER
>>use the VB function as wrapper
But this won't work when the query is called from vb.net, right?
But this won't work when the query is called from vb.net, right?
I suppose not. DSum() is an Access function, not VB/Jet, so it probably isn't available.
If you need the temp table, simply run:
SELECT DeliveryHeaderID, Sum(Cases) As SumCases
INTO zttblDeliveryTotals
Then use zttblDeliveryTotals in your update query. Most large database systems make extensive use of temp tables. No shame there.
(°v°)
If you need the temp table, simply run:
SELECT DeliveryHeaderID, Sum(Cases) As SumCases
INTO zttblDeliveryTotals
Then use zttblDeliveryTotals in your update query. Most large database systems make extensive use of temp tables. No shame there.
(°v°)
ASKER
no no. dsum() DOES work from vb.net.
But you suggestion to use subquery by putting it into a vba code will not run.
temp tables are great when you can use them in sp like in ms sql but using them in code is a big mess, plus u have to cleam them up which you don't have to do in sql server.
But you suggestion to use subquery by putting it into a vba code will not run.
temp tables are great when you can use them in sp like in ms sql but using them in code is a big mess, plus u have to cleam them up which you don't have to do in sql server.
Great, if DSum() works, you are set. What I meant with "wrapping function" was DSum(), although that is not entirely true, not a user-defined function.
So this is sorted out?
Good luck!
(°v°)
So this is sorted out?
Good luck!
(°v°)
ASKER
LOL
allmost, but you know what? NZ won't work!
allmost, but you know what? NZ won't work!
Hmmm.... you get an error, or just not the expected result? You should have the Nz outside, like in: Nz(DSum('cases'.... not DSum('nz(cases)'....
Jet uses the VB function library for most functions and operators, so you can use all built-in VB functions in a Jet query, regardless of the context.
However, user-defined functions are not available as such. They are only when Jet is run from the proper VBA context, i.e. Access. This is why you cannot use them in validation rules, for example.
(°v°)