MS Access DAO Connection Discard Changes On Exit - mysql

So I have this Access form where I use this VBA code with a DAO connection to a MySQL database. Everything works great but if the user closes the form without clicking save button the new record is saved anyway.
So what I'm looking for is if there's any way the on the on close event I can stop the new record being saved to the database?
The code I have,
Private Sub Form_Load()
'Set Form Recordset
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim SQL As String
Set db = OpenDatabase("", False, False, Globales.ConnString)
SQL = "SELECT tbl6Suplidores.ID, tbl6Suplidores.NombreSuplidor, tbl6Suplidores.NumeroComerciante, tbl6Suplidores.DescripcionBienes, tbl6Suplidores.NombreContacto, tbl6Suplidores.NumeroTelefono, tbl6Suplidores.Email " _
& "FROM tbl6Suplidores;"
Set rs = db.OpenRecordset(SQL, dbOpenDynaset, dbAppendOnly)
Set Me.Form.Recordset = rs
End Sub
I'm thinking that since I used the dbAppendOnly it won't let me just delete current record on close event?
Any ideas welcome!
Thanks!

Consider a different approach where you have users enter an unbound form and click a save button to update the MySQL table from populated fields. Exiting form without save will do nothing. This is also a more proactive approach as it allows you to check validation and other logic prior to running save action.
Below uses a parameterized append query with QueryDefs. Also, ID is assumed to be an autonumber and hence left out of query. Sub should be placed behind the OnClick trigger event of save button.
Private Sub SaveButton_Click()
Dim db As DAO.Database, qdef As DAO.QueryDef
Dim SQL As String
Set db = OpenDatabase("", False, False, Globales.ConnString)
' PREPARED STATEMENT WITH NAMED PARAMETERS
SQL = "PARAMETERS ns_param VARCHAR(255), ncom_param INTEGER, db_param VARCHAR(255), " _
& " ncnt_param INTEGER, nt_param INTEGER, e_param VARCHAR(255);" _
& " INSERT INTO (NombreSuplidor, NumeroComerciante, DescripcionBienes, " _
& " NombreContacto, NumeroTelefono, Email) " _
& " VALUES (ns_param, ncom_param, db_param, ncnt_param, nt_param, e_param);"
' INITIALIZE QUERYDEF
Set qdef = db.CreateQueryDef("", SQL)
' BIND PARAMETERS TO FORM FIELDS
qdef!ns_param = Forms!MyFormName!NombreSuplidor
qdef!ncom_param = Forms!MyFormName!NumeroComerciante
qdef!db_param = Forms!MyFormName!DescripcionBienes
qdef!ncnt_param = Forms!MyFormName!NombreContacto
qdef!nt_biens_param = Forms!MyFormName!NumeroTelefono
qdef!e_param = Forms!MyFormName!Email
' RUN ACTION QUERY
qdef.Execute dbFailOnError
Set qdef = Nothing
End Sub

Related

OpenRecordset on a Linked Table?

I split off a few large tables from my AccessDB to a backend database without issue.
Next, I need to open a recordset to replace various troublesome characters. The following snippet worked fine when the table was local, but Access complains now that the table is LINKED, but provides no detail.
Dim rs3 As DAO.Recordset
'Step thru the Item table fix ' & " characters
Set rs3 = db.OpenRecordset("Item", dbOpenTable)
Do While Not rs3.EOF
strDesc = Replace(Nz(rs3!DESC), Chr(39), Chr(39) & Chr(39))
strDesc = Replace(Nz(rs3!DESC), Chr(34), "")
rs3.MoveNext
Loop
Set rs3 = Nothing
Any suggestions for accomplishing this task with a LINKED table?
dbOpenTable can only be used with a local table; it can not be used with a linked table.
'Set rs3 = db.OpenRecordset("Item", dbOpenTable)
Set rs3 = db.OpenRecordset("Item")
'I allways use this format scheme, and it works perfectly, with local or
'linked tables (In fact, I always use linked tables...):
Dim bd As Database
Dim reg As Recordset
Private Sub Form_Load()
Set bd = CurrentDb
Set reg = bd.OpenRecordset("Select * from Pacientes", dbOpenDynaset)
end sub
' for a new record
reg.AddNew
' for updates
reg.Update
' for delete
reg.Delete
' to fill a table record
reg("Dni") = txtDni
' to read a table record
txtDni = reg("Dni")
' txtDni is the field's name in the form
' Dni is the field's name in the table
' to find a record
Dim Finder As String
Finder = InputBox("Dni: ")
If Finder <> "" Then
reg.FindFirst "Dni=" & Trim(Finder)
Private Sub cmdClose_Click()
reg.Close
bd.Close
DoCmd.Close
End Sub

Run Time Error 3464: Data Type Mismatch in criteria expression

I have a form in Access 2010 with Two text boxes(AIPIDTxt to enter the search criteria and AIPResultTxt to display results) and a Button(Search button). I also have a Table Table1 in Access. When I click the Search Button, I need to execute a query whose criteria is in AIPIDTxt Textbox in the form, store the result in a recordset and display the results in the textbox AIPResultTxt. So I typed in the following VBA Code in the Button Event handler.
Private Sub SearchB_Click()
Dim localConnection As ADODB.Connection
Dim query As String
Dim aipid_rs As ADODB.Recordset
Dim db As Database
Set db = CurrentDb
Set localConnection = CurrentProject.AccessConnection
MsgBox "Local Connection successful"
query = "SELECT [AIP Name] FROM [Table1] WHERE [AIP ID]=
" & [Forms]![AIPIDSearchF]![AIPIDTxt] & ""
Set aipid_rs = db.OpenRecordset(query)
Me.AIPResultTxt.Text = aipid_rs![AIP Name]
End Sub
But when I click the button I get Local Connection Successful Message Box and then a Run Time Error 3464 in the line:
Set aipid_rs= db.OpenRecordset(query)
I have searched for similar errors and made corrections. But the error keeps coming. Is there something wrong with my query? Couldn't figure out the error. The table is a local table. So I can directly give [Table1] and field names in the query in vba. Tried adding delimiters because the fields are text fields. But that didn't work as well. I could not give the following query as well:
query = "SELECT [AIP Name] FROM [Table1] WHERE [AIP ID]= " & [Forms]![AIPIDSearchF]!
[AIPIDTxt].Text & ""
This gave me a run time error stating text cannot be referenced from controls that have lost focus. My criteria is text in the text box. The text box loses focus when i click the button. But when I googled for the error, solutions were to remove ".Text". So, I ended up with the above query. Do not know what is wrong with the line:
Set aipid_rs= db.OpenRecordset(query)
I suspect you have more than one problem with that code. But Access complains about only the first problem it finds. Look again at these 2 lines ...
Dim aipid_rs As ADODB.Recordset
Set aipid_rs = db.OpenRecordset(query)
OpenRecordset is a DAO method which returns a DAO recordset. But the code attempts to assign it to aipid_rs which was declared As ADODB.Recordset. Those recordset types are not compatible.
There is an ADO connection object variable, localConnection, which is not used for anything later. Although it doesn't trigger an error, it's just not useful. And actually I don't see any reason to use anything from ADO for this task.
I suggest you try this version of your code ...
'Dim localConnection As ADODB.Connection
'Dim query As String ' query is a reserved word
Dim strQuery As String
'Dim aipid_rs As ADODB.Recordset
Dim aipid_rs As DAO.Recordset
Dim db As Database
Set db = CurrentDb
'Set localConnection = CurrentProject.AccessConnection
'MsgBox "Local Connection successful"
' you said [AIP ID] is text type, so include quotes around
' the text box value
strQuery = "SELECT [AIP Name] FROM [Table1] WHERE [AIP ID]= '" & _
[Forms]![AIPIDSearchF]![AIPIDTxt] & "'"
Debug.Print strQuery
DoCmd.RunCommand acCmdDebugWindow
Set aipid_rs = db.OpenRecordset(strQuery)
'Me.AIPResultTxt.Text = aipid_rs![AIP Name] ' .Text property is only
' available when control has focus; it will trigger
' an error at any other time
Me.AIPResultTxt.Value = aipid_rs![AIP Name]
Note Debug.Print strQuery will display the text of the SELECT statement in the Immediate window, and DoCmd.RunCommand acCmdDebugWindow opens the Immediate window. If you still have a problem with the query, copy the statement text and paste it into SQL View of a new query for testing.
Finally I'm curious whether this might give you what you need with much less code ...
Private Sub SearchB_Click()
Me.AIPResultTxt.Value = DLookup("[AIP Name]", "Table1", _
"[AIP ID]='" & Me.AIPIDTxt & "'")
End Sub
You are using an ADO recordset, therefore your open syntax is incorrect. The following should work for you (except you may get an error setting the text if the control doesn't have focus...)
Dim localConnection As ADODB.Connection
Dim query As String
Dim aipid_rs As ADODB.Recordset
Dim db As Database
Set db = CurrentDb
Set localConnection = CurrentProject.AccessConnection
MsgBox "Local Connection successful"
query = "SELECT [AIP Name] FROM [Table1] WHERE [AIP ID]= '" & [Forms]![AIPIDSearchF]![AIPIDTxt] & "'"
'Set aipid_rs = db.OpenRecordset(query)
Set aipid_rs = New ADODB.Recordset
aipid_rs.Open query, localConnection, adOpenStatic, adLockReadOnly
If Not aipid_rs.EOF Then
Me.AIPResultTxt.Text = aipid_rs![AIP Name]
Else
MsgBox "No records!!"
End If
aipid_rs.Close
Set aipid_rs = Nothing
localConnection.Close
Set localConnection = Nothing
db.Close
Set db = Nothing
OK, So I have been searching for a simple search element for quite awhile...
I have tried using subforms and I have tried recordsets. All of these have given me the information. But not the compactness I was looking for, thanks!!!
using the DOA stuf is great but not for my application.
using the above:
Me.AIPResultTxt.Value = DLookup("[AIP Name]", "Table1", _
"[AIP ID]='" & Me.AIPIDTxt & "'")
I have the compactness of code I was looking for...
THanks!!!
T

How to insert several fields into a table using ADO when two of the fields contain commas

I have an ado created recordset in access 2010 it returns 9 different fields from a stored procedure on sql server 2008 r2.
I am trying to use this recordset (which does populate) to insert all of the records into a table that matches the output. My issue is that two of the fields are name fields that have commas in them. For example Smith, Joseph-- I need to insert that comma into the appropriate field. Right now it throws an error because of the comma in the field.
Here is the code that I am using:
Option Compare Database
'Executes the filtering routine
Private Sub cmdApplyFilter_Click()
'If txtStartDate.Value And txtEndDate.Value Is Not Null Then
' QuickFilter
'Else
' DefaultRun
'End If
QuickFilter
'********** Filter as you type **********
'Private Sub txtFilter_Change()
' QuickFilter
'End Sub
End Sub
'Perform the actual filtering on the subform
Private Sub QuickFilter()
Dim Sql As String
Dim filter As String
If txtStartDate = vbNullString Then
'Reset the filter if the textbox is empty
'This will be the default sql statement to fill the subreport
SubForm.Form.FilterOn = False
Else
'Some common substitutions that users may have already inserted as wildchars
filter = Replace(txtStartDate, "%", "*")
filter = Replace("*" & filter & "*", "**", "*")
'Construct the filter for the sql statement
'/*********** GROUP BY GOES HERE ***********/
'Assign the filter to the subform
'SubForm.Form.filter = Sql
'SubFomr.Form.FilterOn = True
End If
End Sub
Private Sub Form_Load()
'Sets up the connection with the sql server database retrieves the stored procedure, executes it and puts the result set into a table
Dim Conn As ADODB.Connection
Dim Cmd As ADODB.Command
Dim Rs As ADODB.Recordset
Dim rs1 As ADODB.Recordset
Dim Connect As String
Dim filter As String
Connect = "Provider =SQLNCLI10; Data Source=10.50.50.140; Initial Catalog=CCVG; User Id = oe; Password = Orth03c0; "
'Establish the connection with sql server
Set Conn = New ADODB.Connection
Conn.ConnectionString = Connect
Conn.Open
'Open the recorset
Set Cmd = New ADODB.Command
Cmd.ActiveConnection = Conn
Cmd.CommandText = "dbo.cusGenNoNotesReport"
Cmd.CommandType = adCmdStoredProc
Set Rs = Cmd.Execute()
Dim x As Integer
If Not Rs.BOF And Not Rs.EOF Then
If Not Rs.BOF Then Rs.MoveFirst
Do Until Rs.EOF
For x = 0 To Rs.Fields.Count - 1
MsgBox Rs.Fields(x)
'DoCmd.RunSQL "INSERT INTO tblNoNotes (Provider, Facility, TicketNumber, Charges, FinancialClass, CPT, CPTDescription, PatientFullName, DateOfEntry) SELECT " & Rs.Fields(x).Value & ""
Next x
Rs.MoveNext
Loop
End If
'Process results from recordset, then close it.
'DoCmd.RunSQL "INSERT INTO tblNoNotes (Provider, Facility, TicketNumber, Charges, FinancialClass, CPT, CPTDescription, PatientFullName, DateOfEntry) VALUES (""" & Rs![Provider] & """,""" & Rs![Facility] & """ & Rs![TicketNumber] & """, """ & Rs![Charges] & """, """ & Rs![FinancialClass] & """, """ & Rs![CPT] & """, """ & Rs![CPTDescription] & """, """ & Rs![PatientFullName] & """, """ & Rs![DateOfEntry] & """ )"
Rs.Open
Rs.Close
Conn.Close
Set Rs = Nothing
Set Cmd = Nothing
Set Conn = Nothing
End Sub
You have an ADO Recordset, Rs, which contains data you want to add to your Access table. Instead of trying to fix the INSERT statement to add each row, it should be easier to open a DAO Recordset for the destination table and store the values from each ADO row by adding a new row the the DAO Recordset. Although this is still a RBAR (row by agonizing row) approach, it should be significantly faster than building and executing an INSERT statement for each row.
First of all, make sure to add Option Explicit to your module's Declarations section.
Option Compare Database
Option Explicit
Then use this code to append the ADO Recordset data to your table.
Dim db As DAO.Database
Dim rsDao As DAO.Recordset
Set db = CurrentDb
Set rsDao = db.OpenRecordset("tblNoNotes", _
dbOpenTable, dbAppendOnly + dbFailOnError)
Do While Not Rs.EOF
rsDao.AddNew
rsDao!Provider.Value = Rs!Provider.Value
rsDao!Facility.Value = Rs!Facility.Value
rsDao!TicketNumber.Value = Rs!TicketNumber.Value
rsDao!Charges.Value = Rs!Charges.Value
rsDao!FinancialClass.Value = Rs!FinancialClass.Value
rsDao!CPT.Value = Rs!CPT.Value
rsDao!CPTDescription.Value = Rs!CPTDescription.Value
rsDao!PatientFullName.Value = Rs!PatientFullName.Value
rsDao!DateOfEntry.Value = Rs!DateOfEntry.Value
rsDao.Update
Rs.MoveNext
Loop
rsDao.Close
Set rsDao = Nothing
Set db = Nothing
Note this approach means you needn't worry about whether PatientFullName contains a comma, or apostrophe ... or struggle with properly quoting field values to produce a valid INSERT statement. You simply store the value from one recordset field to the appropriate field in another recordset.
I think the real problem you're complaining about here is that your data in the ADO Recordset has quotes (sometimes called apostrophes) in it. Anytime quotes could possibly exist in your data you will need to check for and escape them before using the data in an SQL Statement. You will need to know this not only for inserts but also for performing filtering and creating WHERE statements as well. For example:
Replace(Rs![PatientFullName], "'", "''")
A simpler way to do this is to make your own little function. The "PQ" stands for pad quotes. You can name it whatever you want.
PQ(rs![PatientFullName])
Public Function PQ(s as String) as String
PQ = Replace(s, "'", "''")
End Function
But I also agree with HansUp that it's much easier to use recordsets for inserts. I basically never use SQL Insert statements anymore, except for places where I have no option such as SQL Server T-SQL.
Be aware that if you do want to use insert statements, you should consider using the following:
CurrentDb.Execute "INSERT INTO Statement Goes Here", dbFailOnError
This is considered to be a more robust solution than DoCmd.RunSQL, mostly because it runs in the context of the underlying Database Engine instead of the Access interface. Using CurrentDb.Execute prevents you from having to use DoCmd.SetWarning statements to turn off warnings.

how to use ADO recordset to create new table based on existing table and set the recordset(new table) as form's record source?

i want to use ADO recordset to create new table based on existing table.then i want to set the new table as my form's record source.i know i can create a query and set the query as my form's record source but is it possible if i dont want to use this method? i want the form's record source to exist only when the form load. here's what i've done but still cannot set the form's record source to my recordset.
Private Sub Form_Load()
Dim cnn As ADODB.Connection
Set cnn = CurrentProject.Connection
Dim rst As New ADODB.Recordset
rst.ActiveConnection = cnn
Dim mySql As String
'create tblfrmQryOnHold based on tblOnHold
mySql = "SELECT tblDisposition.ID, tblDisposition.DateRecorded, tblDisposition.OrderNo, tblDisposition.ArticleNo, "
mySql = mySql & "tblDisposition.Description, tblDisposition.Process, tblDisposition.Defects, tblDisposition.RefNo, "
mySql = mySql & "tblDisposition.PostedBy, tblDisposition.Status, tblDisposition.Attachment, tblDisposition.Engineer, "
mySql = mySql & "tblDisposition.Remarks, tblDisposition.ReviewClose, tblDisposition.ScrapNo, tblDisposition.HoldbackNo, "
mySql = mySql & "tblDisposition.ProductionRemarks, tblDisposition.HoldbackQuantity, tblDisposition.HoldbackNum INTO "
mySql = mySql & "frmQryOnHold FROM tblDisposition;"
rst.Open mySql
'set form frmOnHold record source to form frmQryOnHold
Forms![frmOnHold].RecordSource = frmQryOnHold
End Sub
i get this error "operation is not allowed when the object is close", which object this error refer to?
You seem to be working with two different ideas.
Private Sub Form_Load()
Dim cnn As ADODB.Connection
Set cnn = CurrentProject.Connection
Dim rst As New ADODB.Recordset
rst.ActiveConnection = cnn
Dim mySql As String
'create tblfrmQryOnHold based on tblOnHold
''Using aslias t for tblDisposition for clarity
mySql = "SELECT t.ID, t.DateRecorded, t.OrderNo, t.ArticleNo, "
mySql = mySql & "t.Description, t.Process, t.Defects, t.RefNo, "
mySql = mySql & "t.PostedBy, t.Status, t.Attachment, t.Engineer, "
mySql = mySql & "t.Remarks, t.ReviewClose, t.ScrapNo, t.HoldbackNo, "
mySql = mySql & "t.ProductionRemarks, t.HoldbackQuantity, t.HoldbackNum INTO "
mySql = mySql & "frmQryOnHold FROM tblDisposition As t;"
''Action query, so execute it aginst a connection
''This will fail if the table already exists, so it would be
''much better to use DELETE FROM ... and INSERT INTO ...
''which would also cut down or bloat. However, the very best
''solution would be to just use a query on tblDisposition
cnn.Execute mySql
''You now have created the table frmQryOnHold and can use it as #SoupyC
''shows, or, if you wish to use recordset, as you seem to imply, then you want:
With rst
Set .ActiveConnection = cnn
''Something like this
.Source = "select * from frmQryOnHold"
.LockType = adLockOptimistic
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.Open
End With
'set form frmOnHold record source to form frmQryOnHold
Set Forms![frmOnHold].Recordset = rst
'set form frmOnHold record source to form frmQryOnHold
Forms![frmOnHold].RecordSource = frmQryOnHold
End Sub
If you are just assigning a table to a recordsource, pure DAO is the way to go.
You need to put quotes around the RecordSource like this:
Forms![frmOnHold].RecordSource = "frmQryOnHold"

Access query need to bypass "enter parameter value" error with a msg box saying field not found

I have a simple query tied to a command button that shows a summary of the values in a particular field. It's running on a table that changes with each use of the database, so sometimes the table will contain this field and sometimes it won't. When the field (called Language) is not in the file, the user clicks the command button and gets the "Enter Parameter Value" message box. If they hit cancel they then get my message box explaining the field is not present in the file. I would like to bypass the "Enter Parameter Value" and go straight to the message if the field is not found. Here is my code:
Private Sub LangCount_Click()
DoCmd.SetWarnings False
On Error GoTo Err_LangCount_Click
Dim stDocName As String
stDocName = "LanguageCount"
DoCmd.OpenQuery stDocName, acNormal, acEdit
Err_LangCount_Click:
MsgBox "No Language field found in Scrubbed file"
Exit_LangCount_Click:
Exit Sub
DoCmd.SetWarnings True
End Sub
You can attempt to open a recordset based on the query before you run the query:
Set rs = CurrentDb.QueryDefs("query1").OpenRecordset
This will go straight to the error coding if anything is wrong with the query.
Alternatively, if it is always the language field and always in the same table, you can:
sSQL = "select language from table1 where 1=2"
CurrentDb.OpenRecordset sSQL
This will also fail and go to your error coding, but if it does not fail, you will have a much smaller recordset, one with zero records.
You can easily enough get a list of fields in a table with ADO Schemas:
Dim cn As Object ''ADODB.Connection
Dim i As Integer, msg As String
Set cn = CurrentProject.Connection
Set rs = cn.OpenSchema(adSchemaColumns, Array(Null, Null, "Scrubbed"))
While Not rs.EOF
i = i + 1
msg = msg & rs!COLUMN_NAME & vbCrLf
rs.MoveNext
Wend
msg = "Fields: " & i & vbCrLf & msg
MsgBox msg
More info: http://support.microsoft.com/kb/186246
You have a command button named LangCount. It's click event has to deal with the possibility that a field named Language is not present in your Scrubbed table.
So then consider why a user should be able to click that command button when the Language field is not present. When the field is not present, you know the OpenQuery won't work (right?) ... so just disable the command button.
See if the following approach points you to something useful.
Private Sub Form_Load()
Me.LangCount.Enabled = FieldExists("Language", "Scrubbed")
End Sub
That could work if the structure of Scrubbed doesn't change after your form is opened. If the form also includes an option to revise Scrubbed structure, update LangCount.Enabled from that operation.
Here is a quick & dirty (minimally tested, no error handling) FieldExists() function to get you started.
Public Function FieldExists(ByVal pField As String, _
ByVal pTable As String) As Boolean
Dim blnReturn As Boolean
Dim db As DAO.Database
Dim fld As DAO.Field
Dim tdf As DAO.TableDef
Set db = CurrentDb
' next line will throw error #3265 (Item not found in this collection) '
' if table named by pTable does not exist in current database '
Set tdf = db.TableDefs(pTable)
'next line is not actually needed '
blnReturn = False
For Each fld In tdf.Fields
If fld.Name = pField Then
blnReturn = True
Exit For
End If
Next fld
Set fld = Nothing
Set tdf = Nothing
Set db = Nothing
FieldExists = blnReturn
End Function