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

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"

Related

MS Access DAO Connection Discard Changes On Exit

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

Updating SQL Database Using VBA ADODB Connection

I've been using ADODB for SQL queries to return data and copy it from a recordset to a workbook for a while and a new task is to update records but I have no clue on how to do update a record.
This is an example of my code:
Dim con As ADODB.Connection
Dim rec As ADODB.Recordset
Set con = New ADODB.Connection
Set rec = New ADODB.Recordset
Dim sql As String
With con
.Provider = "MSDASQL"
.ConnectionString = "DSN=ukfast"
.Open
End With
sql = "UPDATE crm_clients " & _
"SET cheque_number = '" & chqNo & "' " & _
"WHERE id = '' "
For Selecting data it was as easy as recordset.copyFromRecordset, but I have no clue about pushing an update back up to the database. I tried the .update method but that only works for the record set itself not the database. I've also looked for some sort of execute method but come up short.
What is the correct approach for updating a record using VBA?
You can use the Execute method of the connection object for that:
con.Execute(sql)

How to delete all records of a table in MS Access using VB6 ADO

I want to delete all records of a table in MS Access using VB.6 code.
Actually I'm going to reset my database with it, by that I mean to have NO records anymore.
How can I do that?
I have done it.
On Error Resume Next
Dim cnn As New ADODB.Connection
cnn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\DB.mdb"
cnn.Open
cnn.Execute "delete * from LogTBL"
cnn.Close
Here is code that will delete all records in all tables of the Access database you are connected to. HOWEVER!! If you have built relationships between tables and have not specified 'Cascade Delete', then you can't delete the 'owner' table until deleting from the 'member' table. One way around that is to add an error trap so that you check that condition, then ignore (Resume Next). But then you would need to repeat running this code until no errors. You need to set your connection string (see comment in code)!!
Function Delete_All_Data()
Dim cnLocalData As ADODB.Connection
Dim catLocal As ADOX.Catalog
Dim tdf As ADOX.Table
Dim strSQL As String
Dim strTableName As String
Set cnLocalData = New ADODB.Connection
MsgBox " Add code to connect to your database either using Connection cnLocalData or your own and change this code!!!"
Set catLocal = New ADOX.Catalog
catLocal.ActiveConnection = cnLocalData
For Each tdf In catLocal.Tables
If UCase(tdf.Type) = "TABLE" And UCase(Left(tdf.Name, 4)) <> "MSYS" Then
if tdf.Name <> "INFOTBL" Then
strTableName = tdf.Name
strSQL = "delete * from [" & strTableName & "];"
cnLocalData.Execute strSQL
End If
End If
Next tdf
Set tdf = Nothing
Set catLocal = Nothing
cnLocalData.Close
Set cnLocalData = Nothing
End Function

MS Access Passthrough Query Update

I am trying to make an Update to a Passthrough query using MS Access to an ODBC server that I have no control over. The reason I have to use a Passthrough is that the records I am accessing have more than 255 fields (I would use a linked table if I could).
I've been using this resource to get the data using Passthrough (http://www.techonthenet.com/access/tutorials/passthrough/basics09.php)
The query is simply: SELECT FullName, PointNumber FROM DNP3.CDNP3AnalogIn
The ODBC Connect Str is: ODBC;DSN=SCX6_DB;LOCATION=Main;UID=admin;PWD=password;LOCALTIME=False;
Now inside an Access Database I have a table (SCADA DB Tags) with same name for the Fields (FullName, PointNumber), and I want to update the fields inside the ODBC Database using an Update Passthrough query, but I am unsure how to do this.
I saved the previous Query as DNP3_CDNP3AnalogIn Query, and tried to make a new Query:
UPDATE [DNP3_CDNP3AnalogIn Query] INNER JOIN [SCADA DB Tags] ON
[DNP3_CDNP3AnalogInQuery].FullName = [SCADA DB Tags].FullName
SET [DNP3_CDNP3AnalogIn Query].[PointNumber] = [SCADA DB Tags].[PointNumber];
But I get an error from Access: Operation must use an updateable query.
I know there is someway to do this but I can't seem to find an example (I might not be googling the correct phrase). Microsoft page (http://technet.microsoft.com/en-us/library/bb188204%28v=sql.90%29.aspx) says: There is, however, one important limitation: the results returned by SQL pass-through queries are always read-only. If you want to enable users to perform updates based on the data retrieved, you must write code to handle this. Unfortunately it doesn't give an example to do it!
Can anyone give me a solution, I can use VBA if required? I can also give more background if required. Unfortunately I'm not an expert in Access, I'm just trying to come up with an automated solution that could save me some time.
When they said that "If you want to enable users to perform updates based on the data retrieved [from a pass-through query], you must write code to handle this" they probably meant something like this:
Option Compare Database
Option Explicit
Public Sub UpdateSqlServer()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim con As Object ' ADODB.Connection
Dim cmd As Object ' ADODB.Command
Const adParamInput = 1
Const adInteger = 3
Const adVarWChar = 202
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset( _
"SELECT " & _
"[SCADA DB Tags].FullName, " & _
"[SCADA DB Tags].PointNumber " & _
"FROM " & _
"[DNP3_CDNP3AnalogIn Query] " & _
"INNER JOIN " & _
"[SCADA DB Tags] " & _
"ON [DNP3_CDNP3AnalogIn Query].FullName = [SCADA DB Tags].FullName", _
dbOpenSnapshot)
Set con = CreateObject("ADODB.Connection")
con.Open "DSN=SCX6_DB;"
Set cmd = CreateObject("ADODB.Command")
cmd.ActiveConnection = con
cmd.CommandText = _
"UPDATE DNP3.CDNP3AnalogIn SET " & _
"PointNumber=? " & _
"WHERE FullName=?"
cmd.Parameters.Append cmd.CreateParameter("?", adInteger, adParamInput) ' PointNumber
cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255) ' FullName
cmd.Prepared = True
Do Until rst.EOF
cmd.Parameters(0).Value = rst!PointNumber
cmd.Parameters(1).Value = rst!FullName
cmd.Execute
rst.MoveNext
Loop
Set cmd = Nothing
con.Close
Set con = Nothing
rst.Close
Set rst = Nothing
Set cdb = Nothing
End Sub
Notes:
The code uses your existing ODBC DNS.
It uses a Prepared Statement to perform the updates, increasing efficiency and protecting against failures related to SQL Injection.
The source Recordset performs an INNER JOIN on the pass-through query to ensure that the code only tries to update rows on the server that actually exist on the server.
Are you saying that [DNP3_CDNP3AnalogIn Query] is server side based and that table [SCADA DB Tags] is local based? In that case you cannot use a pass-through query.
However since the tables ARE in different locations pass-though cannot touch BOTH at the same time.
You can however execute "single" server side (pass-though) in a loop. If you setup a pass-though query and SAVE it, then this code will work:
Dim qdfPass As DAO.QueryDef
Dim rstLocal As DAO.Recordset
Dim strSQL As String
Dim strSQL2 As String
Set qdfPass = CurrentDb.QueryDefs("MyPass")
strSQL = "UPDATE [DNP3_CDNP3AnalogIn Query] " & _
"SET [DNP3_CDNP3AnalogIn Query].[PointNumber] = 'xxxx' " & _
"WHERE [DNP3_CDNP3AnalogInQuery].FullName = 'zzzz' "
Set rstLocal = CurrentDb.OpenRecordset("[SCADA DB Tags]")
Do While rstLocal.EOF = False
strSQL2 = Replace(strSQL, "xxxx", rstLocal!PointNumber)
strSQL2 = Replace(strSQL2, "zzzz", rstLocal!FullName)
qdfPass.SQL = strSQL2
qdfPass.Execute
rstLocal.MoveNext
Loop
rstLocal.Close

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.