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)
Related
I have built a program by ms access as a front and save DATA IN sql server database. Also I have some local table in my program.
My program is connected to sql server by connection string and i can read, write, delete and update data.Sometimes I need to copy result of a query to my local table into access and sometimes I want to append one of my access table to sql table
I have written a connection and tried to executed it like this:
Function CopyData()
Dim cn as ADODB.Connection
Dim strServer, strDatabase, strUsername, strPassword As String
Dim strConnectionString As String
strServer = "10.25.2.120"
strDatabase = "dbKala"
strUsername = "javid"
strPassword = "1234"
strConnectionString = "Provider=SQLOLEDB;Data Source=" & strServer & ";Initial Catalog=" & strDatabase & ";User ID=" & strUsername & ";Password=" & strPassword & ";"
Set cn = New ADODB.Connection
cn.ConnectionString = strConnectionString
cn.CommandTimeout = 0
cn.Open
cn.Execute "INSERT INTO GetTelServer Select * FROM dbo.telefone"
End Function
but data isn't copied from sql to access and show me a message about invalid object my access table
I need to help me how to copy a query from sql to access table and vice verse
This task would be a lot easier with linked DAO.Tables, but that needs proper ODBC-Driver for SQL-Server.
If Ms-Access and SQL-Servers bitness match (x64) you can try using OPENROWSET on SQL-Server to access Ms-Access tables from there.
E.g
INSERT INTO SqlServerTable (SqlServerField) SELECT AccessField FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0',
'C:\Program Files\Microsoft Office\OFFICE11\SAMPLES\Northwind.mdb';
'admin';'',AccessTable);
If bitness doesn't match, you have to create 2 different connections and use recordsets (or Action-Query for insert)
One rs is to select the data, second is for inserts:
Dim cn As ADODB.Connection, rs As ADODB.Recordset
Dim cn2 As ADODB.Connection, rs2 As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open "Provider=SQLNCLI11;Server=server;Database=db;Trusted_Connection=yes;"
Set cn2 = New ADODB.Connection
cn2.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Path\To\AccessDb;"
Set rs = cn.Execute("SELECT SqlServerField FROM SQLSERVERTable")
Set rs2 = cn2.Execute("SELECT AccessField FROM AccessTable")
Do Until rs2.Eof
rs.AddNew
rs.Fields("SqlServerField").Value = rs2.Fields("AccessField").Value
rs.Update
rs2.MoveNext
Loop
rs.Close
rs2.Close
cn.Close
cn2.Close
Of course the fields data-types have to be compatible.
I am trying to connect to an Access database 2013 (.accdb) from VB6, and keep getting errors. My code is as follows:
Dim db_file As String
Dim statement As String
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
' Get the data.
db_file = App.Path
If Right$(db_file, 1) <> "\" Then db_file = db_file & "\"
db_file = db_file & "FluidFlo.accdb"
' Open a connection.
Set conn = New ADODB.Connection
conn.ConnectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=" & db_file & ";" & "Persist Security Info=False"
conn.Open '(PROBLEM IS HERE)
' Select the data.
statement = "SELECT strEmpName FROM tblEmployees ORDER BY strEmpName"
' Get the records.
Set rs = conn.Execute(statement, , adCmdText)
' Load the results into the ComboBox
Do Until rs.EOF
cboUsername.AddItem rs!strEmpName
rs.MoveNext
Loop
' Close the recordset and connection.
rs.Close
conn.Close
I am trying to load a table in to a combobox in the program, and assuming my connection string is having an error. I changed the Provider=Microsoft.ACE.OLEDB.12.0; to Provider=Microsoft.ACE.OLEDB.15.0; and still no luck. Keep getting an error.
Does anyone have an idea of how to connect to an .accdb database, whether SQL commands or any? Thanks in advance...(pulling my hair out...)
I am trying to call a udf (SQL server) from Vb code in access. Connection to DB was successful and I am able to run queries on SQL server tables. However, when I try to call the UDF, it throws me an error saying undefined function.
Please see the code below:
Private Sub cmd_Login_Click()
' some code here
Set db = CurrentDb()
sSQL = "SELECT UserID FROM TBL_User_Login WHERE UserName = '" & cbo_User & "' AND Status = 0"
Set recset = db.OpenRecordset(sSQL)
recset.Close
Set rectset = Nothing
sSQL = "SELECT fn_validate_user(" & gb_UserId & ",'" & Hash(Me.txt_Password + cbo_User) & "') AS PasswordValid"
Set recset = db.OpenRecordset(sSQL) ' this is where i get error for undefined function fn_validate_user
PasswordValid = recset("PasswordValid")
Can someone see if I am missing something here.
When you run a standard query in Access it is first processed by the Access Database Engine, even if that query refers to ODBC linked tables. Access can recognize Access user-defined functions (created with VBA) but it is not aware of SQL Server user-defined functions.
In order to use a SQL Server user-defined function you need to use a pass-through query. As the name suggests, it bypasses the Access Database Engine and sends the query directly to the remote database (via ODBC). The VBA code to do that would look something like this:
Dim db As DAO.Database, qdf As DAO.QueryDef, recset As DAO.Recordset
Dim sSQL As String, PasswordValid As Boolean
Set db = CurrentDb
sSQL = "SELECT fn_validate_user(" & gb_UserId & ",'" & Hash(Me.txt_Password + cbo_User) & "') AS PasswordValid"
Set qdf = db.CreateQueryDef("")
' get .Connect property from existing ODBC linked table
qdf.Connect = db.TableDefs("TBL_User_Login").Connect
qdf.ReturnsRecords = True
qdf.SQL = sSQL
Set recset = qdf.OpenRecordset(dbOpenSnapshot)
PasswordValid = recset.Fields("PasswordValid").Value
recset.Close
Set recset = Nothing
Set qdf = Nothing
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
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"