In my code I run a SQL statement in VBA like this:
Dim rs As DAO.Recordset
Dim db As DAO.Database
Set db = CurrentDb
Set rs = CurrentDb.OpenRecordset( SQL-Statement)
This SQL-Statement either returns one value or none.
I then want to check wether a value is returned or not.
If IsError(rs.Fields("Name").Value) = True Then
MsgBox(Error)
Else
Variable = rs.Fields("Name").Value
End If
However: If there is an error the method IsError doesn't return true but the script says runtime-error 3021 and breaks.
Why does the method fail on this?
Unfortunately I have to write this on my mobile since I'm not allowed to log in on platforms from my work PC.
Ty all in Advance
You need to check the EOF property of the recordset.
Try this:
If Not rs.EOF Then Variable = rs.Fields("Name").Value
which is the same as
If Not rs.EOF Then Variable = rs![Name]
Related
Recently I needed to add the parameter dbSeeChanges to the OpenRecordset method of the Database object in order to prepare the system for SQL Server progressive migration.
The thing is that change seemingly altered the functioning of the Recordset object in the following way.
Previously, if I had a Recordset that returned no records and I used the FindFirst method it went smoothly without errors, it simply found nothing and moved on. But now, in this same scenario, that action raises the following runtime error: 3021 "No current record".
Given a recordset with that returns no records the following code runs without errors:
Dim dbCurrDB As Dao.Database
Dim rstA As Recordset
Set dbCurrDB = CurrentDB
Set rstA = dbCurrDB.OpenRecordset("SomeTable", dbOpenDynaset)
With rst
.FindFirst "Id=1"
If .NoMatch=False Then
.Edit
!SomeField=SomeValue
.Uptade
End If
End With
Given the same conditions, the following code raises that 3021 error on the '.FindFirst "Id=1"' instruction:
Dim dbCurrDB As Dao.Database
Dim rstA As Recordset
Set dbCurrDB = CurrentDB
Set rstA = dbCurrDB.OpenRecordset("SomeTable", dbOpenDynaset, dbSeeChanges)
With rst
.FindFirst "Id=1"
If .NoMatch=False Then
.Edit
!SomeField=SomeValue
.Uptade
End If
End With
I know how to solve the issue (although it will finally force me to correct all legacy...). What I want is to understand why this happens. What exactly did change? Something with the pointer of the Recordset object? And also, if there can be other unintended side effects.
I wonder if there are some detailed technical specifications for DAO that can show me what the heck really happens with the mehods of the Recordset object behind the scenes.
Thanks in advance!
Check for records, or there is nothing to find:
With rst
If .RecordCount > 0 Then
.FindFirst "Id=1"
If .NoMatch = False Then
.Edit
!SomeField.Value = SomeValue
.Update
End If
End If
.Close
End With
I have a form that creates two queries, exports them to Excel and then deletes them. However, when I hit an error on my exporting, it doesn't make it the deletions. How would I go about checking to see if they already exist? And if they do, delete them so I can re-create them with the new/updated data?
Code so far:
Dim qdfNewQry As Object
Dim qdfNewWS As Object
'//----- qdfNewQry
If Not IsNull(DLookup("myExportQry", "MSysObjects", "Name='myExportQry'")) Then
CurrentDb.QueryDefs.Delete qdfNewQry.Name
Set qdfNewQry = CurrentDb.CreateQueryDef("myExportQry", exportQry)
Else
Set qdfNewQry = CurrentDb.CreateQueryDef("myExportQry", exportQry)
End If
'//----- qdfNewWS
If Not IsNull(DLookup("myExportWS", "MSysObjects", "Name='myExportWS'")) Then
CurrentDb.QueryDefs.Delete qdfNewWS.Name
Set qdfNewWS = CurrentDb.CreateQueryDef("myExportWS", exportWS)
Else
Set qdfNewWS = CurrentDb.CreateQueryDef("myExportWS", exportWS)
End If
I'm getting the error "The expression you entered as a query parameter produced this error: 'myExportQry'" on the line If Not IsNull(DLookup("myExportQry", "MSysObjects", "Name='myExportQry'")) Then
I'm pretty lost it seems. Any help/advice/corrections would be greatly appreciated!
EDIT1:
Just for clarification, I'm wanting to delete the entire query. Other alternative solutions would also be welcome!
I wouldn't use the Dlookup function for this!
Private Sub Command1_Click()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb()
For Each qdf In db.QueryDefs
Debug.Print qdf.Name
If qdf.Name = "strQry" Then
CurrentDb.QueryDefs.Delete "strQry"
CurrentDb.QueryDefs.Refresh
Exit For
End If
Next qdf
Set qdf = Nothing
Set db = Nothing
End Sub
DLookup uses the following format:
DLookup([Field], [Table], [Criteria])
There's no field in MSysObjects named "MyExportQuery". So, the first argument in DLookup() is wrong.
Also, remember that when you use a reserved word (like "Name"), you need to enclose it in brackets.
I think you want to say,
DLookup("[ID]", "MSysObjects", "[Name]='myExportQry'")
That should either return a number or a NULL, so that will give you what you need to determine if the query already exists.
The above is untested, but logically it makes sense to me.
I use this. If the query is not there the DeleteObject will be "skipped"
On Error Resume Next
DoCmd.DeleteObject acQuery, "myExportQry"
Set qdfTemp = CurrentDb.CreateQueryDef("myExportQry", "SELECT From ....")
I have code that looks like this:
If BLAH=BLAH
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim qdf As DAO.QueryDef
...rest of code...
'Close stuff
rst.Close
dbs.Close
Set dbs = Nothing
Set rst = Nothing
Set qdf = Nothing
END IF
If FOO=FOO
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim qdf As DAO.QueryDef
...rest of code...
'Close stuff
rst.Close
dbs.Close
Set dbs = Nothing
Set rst = Nothing
Set qdf = Nothing
END IF
But in the FOO=FOO section, it highlighted dbs As DAO.Database and gave a pop-up error message that says
Compile error: duplicate declaration in current scope.
What am I doing wrong? I thought this would be ok because I am negating each object before re-using. The overarching goal is to run a ton of IF statements on the Form Timer event. Do I need to maybe just declare some objects only once at the top of the event procedure to get around this error?
To clear this issue up in the case of VBA, variable declares are global to the given sub/function routine, or even to the given module.
For most here, the posters question seems strange, but keep in mind that in vb.net the variable definctions are LOCAL to a if/then block of code as posted.
This in VBA, this fails, but in vb.net, it is perfectally legal:
If True Then
Dim a As Long
a = 5
End If
If True Then
Dim a As Long
a = 6
End If
And if you wanted the variable able to be used in both if/then blocks, then you would use this:
Dim a As Long
If True Then
a = 5
End If
If True Then
a = 6
End If
So in VBA, variable scope is local to the function/subroutine. In vb.net the scope is local to the if/then block. This means in some programming languages you can declare a variable several times in a function/subroutine and not receive any compile errors – even when option explicit is in effect. I should also point out that in the above vb.net code examples when code drops out of the if/then block, then the given variable in the first code example goes out of scope. So in VBA, variable declares are not local to a if/then block. I should also point out that I used the word “local” scope, since the if/then code is compiled, and the if/then of the “dim” statement does NOT occur at runtime, but at compile time. In other words, "true" or "false" does not mean the "dim" and declare of the variable does not occur, but only that the variable is "local" to the if/then block. The dim statement does NOT run conditional and is created at compile time.
I am fetching a set of names from a database query and then reformatting it to a comma separated list. As I am using this functionallity a few Places in my app, I try to write it as a function getting the sql-query and returning the string.
Public Function String_from_query(StrSQL As String) As String
Dim dbs As Database
Dim rs As Recordset
Set dbs = CurrentDb
Dim results As String
results = ""
Set rs = dbs.OpenRecordset(StrSQL)
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Do While Not rs.EOF
If results > "" Then
results = results & ", "
End If
results = results & rs("Navn")
rs.MoveNext
Loop
End If
Set String_from_query = results
End Function
This is then called from an event handler:
Private Sub Detalj_Format(Cancel As Integer, FormatCount As Integer)
Dim StrSQL As String
StrSQL = "SELECT Personer.Navn FROM Personer INNER JOIN Personoppgaver ON Personer.Initialer = Personoppgaver.Initialer WHERE Personoppgaver.Oppgaveid =" & Me.Oppgaveid.Value
Me.Tekst52.Value = String_from_query(StrSQL)
End Sub
If I have the code from the String_from_query function within the event handler and then directly assigns Me.Tekst52 to results, everything works fine. When I refactor the code as shown, I get a "Compile Error, Object required" when I try to run it and a marker on the last line in the sub. (Set String_from_query = results). I am not able to see what is wrong. Any help?
The keyword Set is only required when assigning variables to an Object. For Access, this would be Forms, Reports, Recordsets, etc. Or other Objects outside of Access (FileSystemObject, for example).
When setting strings, dates, numbers, etc, you do not need Set.
You can surmise this from the error message as well, Object required.
I'm having an issue with the following lines of code, I feel its something simple but I can't put my finger on it. I get a Run-time error '91' object variable or with block variable not set error. The error happens on the rsc.OpenRecordSet... line. BadgeV is a number, I have the DAO reference installed, It is pulling from a linked sql server table where I have a primary key and identity. What am I missing?
Function FNC_Scan()
Dim db As DAO.Database
Dim rsc As DAO.Recordset
Set db = CurrentDb()
rsc.OpenRecordset ("SELECT dbo_ScanData.CardID, dbo_ScanData.Complete FROM dbo_ScanData WHERE (((dbo_ScanData.CardID)= Forms![Scan]!BadgeV))) AND ((dbo_ScanData.Complete)=0));")
If rsc.EOF Then
MsgBox "new item"
Else
MsgBox "Append Item"
End If
Set rsc = Nothing
Set db = Nothing
End Function
Should be
set rsc = db.OpenRecordset(...)
instead of
rsc.OpenRecordset(...)