VBA SQL Where IS NULL - sql

Im trying to create a VBA sql string with the where clause using inputs from an access form. I need the code to still run properly even if one of the user inputs is null/unselected. The code below runs correctly when all user inputs have been selected but when one input is null/unselected the query ends up pulling back all the records in the table.
Dim SQL As String
SQL = "SELECT qry_1.field1, qry_1.field2, qry_1.field3 INTO recordset FROM qry_1" & _
" WHERE ((qry_1.Field1) IS NULL OR (qry_1.Field1) = '" & [Forms]![frm_Parameters]![cmbx_1] & "') " &_
" AND ((qry_1.Field2) IS NULL OR (qry_1.Field2) = '" & [Forms]![frm_Parameters]![cmbx_2] & "' ) " & _
" AND ((qry_1.Field3) IS NULL OR (qry_1.Field3) = '" & [Forms]![frm_Parameters]![cmbx_3] & "') ;"
DoCmd.RunSQL SQL

It is better to escape single apostrophes in the text for two reasons
You might get an invalid SQL statement if you don't.
A nasty user could can inject evil code (see: SQL injection).
Therefore I use this function
Public Function SqlStr(ByVal s As String) As String
'Input: s="" Returns: NULL
'Input: s="abc" Returns: 'abc'
'Input: s="x'y" Returns: 'x''y'
If s = "" Then
SqlStr = "NULL"
Else
SqlStr = "'" & Replace(s, "'", "''") & "'"
End If
End Function
To account for empty entries, create the condition like this:
Dim cond As String, sql As String
If Nz([Forms]![frm_Parameters]![cmbx_1]) <> "" Then
cond = "qry_1.field1 = " & SqlStr(Nz([Forms]![frm_Parameters]![cmbx_1]))
End If
If Nz([Forms]![frm_Parameters]![cmbx_2]) <> "" Then
If cond <> "" Then cond = cond & " AND "
cond = cond & "qry_1.field2 = " & SqlStr(Nz([Forms]![frm_Parameters]![cmbx_2]))
End If
If Nz([Forms]![frm_Parameters]![cmbx_3]) <> "" Then
If cond <> "" Then cond = cond & " AND "
cond = cond & "qry_1.field3 = " & SqlStr(Nz([Forms]![frm_Parameters]![cmbx_3]))
End If
sql = "SELECT qry_1.field1, qry_1.field2, qry_1.field3 INTO recordset FROM qry_1"
If cond <> "" Then
sql = sql & " WHERE " & cond
End If
This assumes that you want to test a condition only when the corresponding field is not empty.
If you have date constants, format them the Access-SQL way as #2018-08-21# with
Format$(date, "\#yyyy-MM-dd\#")

DoCmd.RunSQL is for action queries (UPDATE, INSERT, DELETE).
To answer the question, here is what I would do:
Nz(Field1,Nz([Forms]![frm_Parameters]![cmbx_1]))=Nz([Forms]![frm_Parameters]![cmbx_1])
That will create equality if either Field1 or [Forms]![frm_Parameters]![cmbx_1] is NULL without breaking the rest of the query.
To use that in VBA:
"Nz(Field1,'" & Nz([Forms]![frm_Parameters]![cmbx_1]) & "')='" & Nz([Forms]![frm_Parameters]![cmbx_1]) & "'"
Also see comment in Olivier Jacot-Descombes answer about taking single quotes in your strings into account.

Related

Search button using more than one text field Access vba

This is my code below. I am trying to search a database using two different dates, company name
I am getting an error when one of the date fields is empty or null. How can I solve this issue or bypass if the date search field is empty to ignore it in the search or search for an empty field?
Dim SQL As String
SQL = "SELECT * from qryRequestInternal where ([DateRequestSent] = #" & txt_Search_Sdate & "# AND [DateReceived] = #" & txt_Search_Rdate & "# AND (companyName like ""*" & txt_SCompNa & "*"") )"
Me.sfrmRequestInternal.Form.RecordSource = SQL
Me.sfrmRequestInternal.Form.Requery
Me.sfrmRequestInternal_col.Form.RecordSource = SQL
Me.sfrmRequestInternal_col.Form.Requery
End Sub
You will need to check for Null values and build the SQL string based on the controls which have a value (i.e. not null).
The example below uses a helper function to build the sql string. If nothing is inserted, it will only run the the Select * from qryRequestInternal without any criteria.
Private Function SqlWhere() As String
Dim retvalue As String
'sent date
With txt_Search_Sdate
If Not IsNull(.Value) Then
retvalue = " WHERE [DateRequestSent] = #" & Format(.Value, "mm/dd/yyyy") & "#"
End If
End With
'received date
With txt_Search_Rdate
If Not IsNull(.Value) Then
retvalue = IIf(Len(retvalue) = 0, " WHERE", retvalue & " AND") & " [DateReceived] = #" & Format(.Value, "mm/dd/yyyy") & "#"
End If
End With
'company
With txt_SCompNa
If Not IsNull(.Value) Then
retvalue = IIf(Len(retvalue) = 0, " WHERE", retvalue & " AND") & " [companyName] Like '*" & .Value & "*'"
End If
End With
SqlWhere = retvalue
End Function
To call it:
Dim sqlString As String
sqlString = "SELECT * from qryRequestInternal" & SqlWhere()
Debug.Print sqlString

How can I resolve runtime error 3075 in VBA

I have problem running this code. It gives me Syntax error (missing operator) in query expression
Function SearchCriteria()
Dim class,StateProvince,strAcademicYear As As String
Dim task, strCriteria As String
If isNull(Forms!frmStudentList!cboClass) Then
Class = "[Class] LIKE '*' "
Else
Class = [Class] = " & Forms!frmStudentList!cboClass
End If
If isNull(Forms!frmStudentList!cboStateProvince) Then
StateProvince = "[StateProvince] LIKE '*' "
Else
StateProvince = [StateProvince] = " &
Forms!frmStudentList!cboStateProvince
End If
If isNull(Forms!frmStudentList!cboAcademicYear) Then
StrAcademicYear = "[AcademicYear] LIKE '*' "
Else
StrAcademicYear = [AcademicYear] = '" &
Forms!frmStudentList!cboAcademicYear & "'"
End If
strCriteria = Class & "AND" & StateProvince & "AND" & StrAcademicYear
task = "SELECT * FROM QryStudentSearch WHERE & Criteria
Forms!frmStudentList.RecordSource = task
Forms!frmStudentList.Requery
End Function
There are quite a few problems with this piece of code.
Firstly, most of your variables aren't explicitly declared as being of a type, so default to being Variant.
Next, Class is a reserved word in Access, and will probably cause you problems.
If a control has no choice made, you are using LIKE '*' to select data. There is no need to do this, as by applying no filter means that all records will be returned anyway.
As it doesn't return a value, you can create this as a Sub rather than a Function.
The main problem is with how you are concatenating the different parts together.
I would rewrite the code as:
Sub sSearch()
Dim strSearch As String
If Not IsNull(Forms!frmStudentList!cboClass) Then
strSearch = strSearch & " AND [Class]='" & Forms!frmStudentList!cboClass & "' "
End If
If Not IsNull(Forms!frmStudentList!cboStateProvince) Then
strSearch = strSearch & " AND [StateProvince]='" & Forms!frmStudentList!cboStateProvince & "' "
End If
If Not IsNull(Forms!frmStudentList!cboAcademicYear) Then
strSearch = strSearch & " AND [AcademicYear]='" & Forms!frmStudentList!cboAcademicYear & "' "
End If
If Left(strSearch, 4) = " AND" Then
strSearch = "WHERE " & Mid(strSearch, 6)
End If
strSearch = "SELECT * FROM qryStudentSearch " & strSearch
Forms!frmStudentList.RecordSource = strSearch
Forms!frmStudentList.Requery
End Sub
In each case, I am assuming that the bound column of each combo box is text, hence the need to use single quotes around the data. If the bound column is numeric, then the single quotes can be removed.
Regards,

Using keywords to find records and list them in a listbox

I have a form (frmSearch) that I use several (4) comboboxes to filter out results for a listbox (lstCustomers). What I'm attempting to do now is create the ability to filter the listbox based on a text box of "keywords". Additionally, the column which the keyword box will search will be variable based on cboWhere which is a list of columns from tblContacts (the table qryContactWants uses)
I found a really nice Function set with the following code that will let me filter everything, but I'm not entirely sure how to turn this data around and use it to filter out my listbox.
This function organizes the keywords:
Public Function FindAnyWord(varFindIn, strWordList As String) As Boolean
Dim var
Dim aWords
aWords = Split(strWordList, ",")
For Each var In aWords
If FindWord(varFindIn, var) Then
FindAnyWord = True
Exit Function
End If
Next var
End Function
And this function actually performs the search:
Public Function FindWord(varFindIn As Variant, varWord As Variant) As Boolean
Const PUNCLIST = """' .,?!:;(){}[]-—/"
Dim intPos As Integer
FindWord = False
If Not IsNull(varFindIn) And Not IsNull(varWord) Then
intPos = InStr(varFindIn, varWord)
' loop until no instances of sought substring found
Do While intPos > 0
' is it at start of string
If intPos = 1 Then
' is it whole string?
If Len(varFindIn) = Len(varWord) Then
FindWord = True
Exit Function
' is it followed by a space or punctuation mark?
ElseIf InStr(PUNCLIST, Mid(varFindIn, intPos + Len(varWord), 1)) > 0 Then
FindWord = True
Exit Function
End If
Else
' is it precedeed by a space or punctuation mark?
If InStr(PUNCLIST, Mid(varFindIn, intPos - 1, 1)) > 0 Then
' is it at end of string or followed by a space or punctuation mark?
If InStr(PUNCLIST, Mid(varFindIn, intPos + Len(varWord), 1)) > 0 Then
FindWord = True
Exit Function
End If
End If
End If
' remove characters up to end of first instance
' of sought substring before looping
varFindIn = Mid(varFindIn, intPos + 1)
intPos = InStr(varFindIn, varWord)
Loop
End If
End Function
And here is the code that I typically use to filter the listbox using the comboboxes on frmSearch:
Dim column As String
SQL = "SELECT qryContactWants.ID, qryContactWants.FullName, qryContactWants.Type, qryContactWants.Make, qryContactWants.Model, qryContactWants.YearWanted, qryContactWants.Condition " _
& "FROM qryContactWants " _
& "WHERE 1=1 "
If cboType.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Type = '" & cboType.Value & "'"
End If
If cboMake.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Make = '" & cboMake.Value & "'"
End If
If cboModel.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Model = '" & cboModel.Value & "'"
End If
If cboYear.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.YearWanted = '" & cboYear.Value & "'"
End If
If cboCondition.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Condition = '" & cboCondition.Value & "'"
End If
SQL = SQL & " ORDER BY qryContactWants.Last"
Me.lstCustomers.RowSource = SQL
Me.lstCustomers.Requery
End Sub
What I would like to do is take the functions I found for searching keywords and apply it to my form and aid in returning a list of customers in lstCustomers
Ideally, having the keyword function return an SQL statement similar to those I'm using to filter out the listbox would be perfect. This would allow me to add a simple SQL = SQL & "AND qryContactWants.VARIABLECOLUMNHERE =SOMETHING
EDIT 1:
While using the following code, VBA is tossing a compile error on the second "End If" stating there isn't a Block If. There clearly is, so I'm not sure what's going on. Here is the code I'm using:
Public Function KeyWhere(strKeys As String, strColumn As String) As String
Dim b As Variant
strKeys = Replace(strKeys, vbCrLf, ",") ' remove all line returns
b = Split(strKeys, ",")
Dim strWhere As String
Dim v As Variant
For Each v In b
If Trim(b) <> "" Then
If strWhere <> "" Then strWhere = strWhere & " or "
strWhere = strWhere & strColumn & " like '*" & Trim(v) & "*'"
End If
End If
Next
strWhere = "(" & strWhere & ")"
KeyWhere = strWhere
End Function
And under the function RequerylistCustomers() I added the If IsNull (Me.txtSearch) = False Then code below:
Private Sub RequerylstCustomers()
Dim SQL As String
'Dim criteria As String
Dim column As String
SQL = "SELECT qryContactWants.ID, qryContactWants.FullName, qryContactWants.Type, qryContactWants.Make, qryContactWants.Model, qryContactWants.YearWanted, qryContactWants.Condition " _
& "FROM qryContactWants " _
& "WHERE 1=1 "
If cboType.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Type = '" & cboType.Value & "'"
End If
If cboMake.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Make = '" & cboMake.Value & "'"
End If
If cboModel.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Model = '" & cboModel.Value & "'"
End If
If cboYear.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.YearWanted = '" & cboYear.Value & "'"
End If
If cboCondition.Value & "" <> "" Then
SQL = SQL & " AND qryContactWants.Condition = '" & cboCondition.Value & "'"
End If
Dim strWhere As String
'Grab Keywords from txtSearch using cboWhere to search for those keywords
If IsNull(Me.txtSearch) = False Then
strWhere = KeyWhere(Me.txtSearch, Me.cboWhere)
SQL = SQL & " AND " & strWhere
End If
SQL = SQL & " ORDER BY qryContactWants.Last"
Me.lstCustomers.RowSource = SQL
Me.lstCustomers.Requery
End Sub
Are the keywords to be searched in a single column (say a comments or memo column?). If yes, then you should be able to optional "add" the one additional criteria to your current "set" of combo box filters.
Are we to assume that the keywords can appear anywhere in that memo column to search?
So, if there are "key words entered into that text box, then you call KeyWhere.
eg this routine:
Public Function KeyWhere(strKeys As String, strColumn As String) As String
Dim b As Variant
strKeys = Replace(strKeys, vbCrLf, ",") ' remove all line returns
b = Split(strKeys, ",")
Dim strWhere As String
Dim v As Variant
For Each v In b
if trim(v) <> "" then
If strWhere <> "" Then strWhere = strWhere & " or "
strWhere = strWhere & strColumn & " like '*" & Trim(v) & "*'"
end if
Next
strWhere = "(" & strWhere & ")"
KeyWhere = strWhere
End Function
We assume each key word is separated by a comma (could be space, but comma is better).
So, if I type in the following command in debug window to test the above?
? keywhere("Generator, Water maker, Battery","Notes")
OutPut:
(Notes like '*Generator*' or Notes like '*Water maker*' or Notes like '*Battery*')
So, we just append the above results to your final SQL.
eg:
dim strWhere as string
if isnull(me.KeyWordBox) = False then
strWhere = keyWhere(me.KeyWordBox,me.cboColumnToSearch)
SQL = SQL & " AND " & strWhere
end if
so, the above converts all keywords into a valid SQL condition for the column to search. It is likely that column is some kind of notes column, but it would work for other description type field to search.

VBA RecordSet function takes too much time to update record using RecordCount

I have one table and one query. Both have the same data field but table COLUMN names are equal to query's ROW name. I update table from query's row data using the following code successfully but it takes too much time to update as there are more than 50 columns name in the table for each employee-
Set rst1 = CurrentDb.OpenRecordset("SELECT * FROM tblPayRollDataTEMP")
Set rst2 = CurrentDb.OpenRecordset("SELECT * FROM qryEmpVerifySalary ")
Do Until rst1.EOF
rst2.MoveFirst
Do Until rst2.EOF
For l = 0 To rst1.Fields.count - 1
If rst1!EmpID = rst2!EmpID And rst1.Fields(l).Name = rst2!Head And rst1!PayBillID = TempVars!BillID Then
With rst1
rst1.Edit
rst1.Fields(l).Value = rst2!Amount
rst1!totDeductions = DSum("Amount", "qryEmpVerifySalary", "[PayHeadType] = 'Deductions' AND [EmpID] = " & rst2!EmpID & "") + DLookup("NPS", "qryEmpPayEarning", "[EmpID] = " & rst2!EmpID & "")
rst1!totRecoveries = DSum("Amount", "qryEmpVerifySalary", "[PayHeadType] = 'Recoveries' AND [EmpID] = " & rst2!EmpID & "")
rst1!NetPayable = rst1!totEarnings - (Nz(rst1!totDeductions, 0) + Nz(rst1!totRecoveries, 0))
rst1.Update
End With
End If
Next
rst2.MoveNext
Loop
rst1.MoveNext
Loop
Set rst1 = Nothing
Set rst2 = Nothing
How to improve the performance of the code?
You should use a query to update your records. This would be the fastest solution. Normally one would match the EmpID and drag and drop the fields into the update query or use an expression. If you have to group before or other complex stuff split it in more querys (two or three). It doesnt matter thou, because in the end you just execute one update query.
For your code, you can replace the domainaggregate functions. DLookup(), DSum(), etc... these are worst for performance. A simple select statement runs way faster than DLookup(). Here are a few replacements:
Function DCount(Expression As String, Domain As String, Optional Criteria) As Variant
Dim strSQL As String
strSQL = "SELECT COUNT(" & Expression & ") FROM " & Domain
'Other Replacements:
'DLookup: strSQL = "SELECT " & Expression & " FROM " & Domain
'DMax: strSQL = "SELECT MAX(" & Expression & ") FROM " & Domain
'DMin: strSQL = "SELECT SUM(" & Expression & ") FROM " & Domain
'DFirst: strSQL = "SELECT FIRST(" & Expression & ") FROM " & Domain
'DLast: strSQL = "SELECT LAST(" & Expression & ") FROM " & Domain
'DSum: strSQL = "SELECT SUM(" & Expression & ") FROM " & Domain
'DAvg: strSQL = "SELECT AVG(" & Expression & ") FROM " & Domain
If Not IsMissing(Criteria) Then strSQL = strSQL & " WHERE " & Criteria
DCount = DBEngine(0)(0).OpenRecordset(strSQL, dbOpenForwardOnly)(0)
End Function

Run-time error '3144': Syntax Error in Update Statement

I'm running into some issues with my update statement, the Add statement seems to work but I keep getting a syntax error in update. I am new to SQL and VBA so a lot of this probably looks like sphagetti code. If anyone can Identify what I did wrong that would be much appreciated. If there is a better way to do it, please let me know.
Private Sub btnSubmit_Click()
Dim mbrName As String
Dim mbrOffice As String
Dim mbrRank As String
Dim mbrOpType As String
Dim mbrRLA As String
Dim mbrMQT As String
Dim mbrPos As String
Dim sqlAdd As String
Dim sqlUpdate As String
If Me.opgMngRoster.Value = 1 Then
'-Set Middle Name to NMI if blank
If IsNull(Me.txtMidInit.Value) Then
Me.txtMidInit.Value = "NMI"
End If
'-Create Member's Name string in all uppercase
mbrName = UCase(Me.txtLastName.Value & ", " & Me.txtFirstName.Value & " " & Me.txtMidInit)
'-Member's Office
mbrOffice = Me.cbxOffice.Value
'-Member's Rank
mbrRank = Me.cbxRank.Value
'-Member's Operator Type
mbrOpType = Me.cbxOpType
'-Member's RLA
mbrRLA = Me.cbxRLA.Value
'-Member's MQT Program
mbrMQT = Me.cbxMQT.Value
'-Member's MQT Position
mbrPos = Me.cbxTngPos.Value
'ADD MEMBER TO ROSTER
sqlAdd = "INSERT INTO [ROSTER] (MEMBER, OFFICE, RANK, OPTYPE, RLA, [MQT-PROGRAM], [MQT-POSITION]) VALUES ('" & mbrName & "', '" & mbrOffice & "', '" & mbrRank & "', '" & mbrOpType & "', '" & mbrRLA & "', '" & mbrMQT & "', '" & mbrPos & "');"
DoCmd.RunSQL (sqlAdd)
'-Confirmation Msg
MsgBox ("Added: " & mbrName)
Else
'-Set Middle Name to NMI if blank
If IsNull(Me.txtMidInit.Value) Then
Me.txtMidInit.Value = "NMI"
End If
'-Create Member's Name string in all uppercase
mbrName = UCase(Me.txtLastName.Value & ", " & Me.txtFirstName.Value & " " & Me.txtMidInit)
'-Member's Office
mbrOffice = Me.cbxOffice.Value
'-Member's Rank
mbrRank = Me.cbxRank.Value
'-Member's Operator Type
mbrOpType = Me.cbxOpType
'-Member's RLA
mbrRLA = Me.cbxRLA.Value
'-Member's MQT Program
mbrMQT = Me.cbxMQT.Value
'-Member's MQT Position
mbrPos = Me.cbxTngPos.Value
'Update Member Data
sqlUpdate = "UPDATE [ROSTER] (MEMBER, OFFICE, RANK, OPTYPE, RLA, [MQT-PROGRAM], [MQT-POSITION]) VALUES ('" & mbrName & "', '" & mbrOffice & "', '" & mbrRank & "', '" & mbrOpType & "', '" & mbrRLA & "', '" & mbrMQT & "', '" & mbrPos & "');"
Debug.Print sqlUpdate
DoCmd.RunSQL sqlUpdate
MsgBox ("Updated: " & mbrName)
End If
End Sub
Several general coding and specific MS Access issues with your setup:
First, no need to repeat your VBA variable assignments for both If and Else blocks. Use DRY-er code (Don't Repeat Yourself).
Also, since you do not apply further calculations, there is no need to assign the majority of form textbox and combobox values to separate string variables. Use control values directly in query.
Use parameterization (an industry best practice) which is not only for MS Access but anywhere you use dynamic SQL in an application layer (VBA, Python, PHP, Java, etc.) for any database (Postgres, SQL Server, Oracle, SQLite, etc.). You avoid injection and any messy quote enclosure and data concatenation.
While languages have different ways to bind values to parameters, one way in MS Access is to use querydef parameters as demonstrated below.
Save your queries as stored objects with PARAMETERS clause (only compliant in MS Access SQL dialect). This helps abstract code from data.
Finally, properly use the update query syntax: UPDATE <table> SET <field>=<value> ...
Insert SQL Query (with parameterization, save once as stored query)
PARAMETERS MEMBER_Param TEXT, OFFICE_Param TEXT, RANK_Param TEXT, OPTYPE_Param TEXT,
RLA_Param TEXT, MQT_PROGRAM_Param TEXT, MQT_POSITION_Param TXT;
INSERT INTO [ROSTER] (MEMBER, OFFICE, RANK, OPTYPE, RLA, [MQT-PROGRAM], [MQT-POSITION])
VALUES (MEMBER_Param, OFFICE_Param, RANK_Param, OPTYPE_Param,
RLA_Param, MQT_PROGRAM_Param, MQT_POSITION_Param);
Update SQL Query (with parameterization, save once as stored query)
PARAMETERS MEMBER_Param TEXT, OFFICE_Param TEXT, RANK_Param TEXT, OPTYPE_Param TEXT,
RLA_Param TEXT, MQT_PROGRAM_Param TEXT, MQT_POSITION_Param TXT;
UPDATE [ROSTER]
SET MEMBER = MEMBER_Param, OFFICE = OFFICE_Param, RANK = RANK_Param,
OPTYPE = OPTYPE_Param, RLA = RLA_Param, [MQT-PROGRAM] = MQT_PROGRAM_Param,
[MQT-POSITION] = MQT_POSITION_Param;
VBA (no SQL shown)
Dim mbrName As String, myquery As String, mymsg As String
Dim qdef As QueryDef
'-Set Middle Name to NMI if blank
If IsNull(Me.txtMidInit.Value) Then
Me.txtMidInit.Value = "NMI"
End If
'-Create Member's Name string in all uppercase
mbrName = UCase(Me.txtLastName.Value & ", " & Me.txtFirstName.Value & " " & Me.txtMidInit)
If Me.opgMngRoster.Value = 1 Then
myquery = "myRosterInsertQuery"
mymsg = "Added: " & mbrName
Else
myquery = "myRosterUpdateQuery"
mymsg = "Updated: " & mbrName
End If
' ASSIGN TO STORED QUERY
Set qdef = CurrentDb.QueryDefs(myquery)
' BIND PARAMS
qdef!MEMBER_Param = mbrName
qdef!OFFICE_Param = Me.cbxOffice.Value
qdef!RANK_Param = Me.cbxRank.Value
qdef!OPTYPE_Param = Me.cbxOpType
qdef!RLA_Param = Me.cbxRLA.Value
qdef!MQT_PROGRAM_Param = Me.cbxMQT.Value
qdef!MQT_POSITION_Param = Me.cbxTngPos.Value
qdef.Execute dbFailOnError
'-Confirmation Msg
MsgBox mymsg, vbInformation
Set qdef = Nothing