MS Access linked table insert transaction commit - sql-server

I have an Access 2016 database that started off as a classic access MDB. Along the way, it was converted to a .accdb, and linked to a backend SQL Server. All of the tables used were converted to linked tables.
There is code that performs code something like this:
sql = "insert into [TableA]..."
CurrentDB.Execute sql
DoCmd.OpenReport(...)
What I'm finding is that intermittently the Insert into the backend SQL doesn't seem to complete before the OpenReport command selects the data from the same table.
Would it be reasonable to solve this by using. Assuming my issue is that the data is not committed to the SQL table in time for the Report Execution to see it, would the following code insure this?
sql = "insert into [TableA]..."
CurrentProject.Connection.BeginTrans
CurrentProject.Connection.Execute sql
CurrentProject.Connection.CommitTrans
DoCmd.OpenReport(...)

If you're using ADO, you can use the RecordsAffected output parameter to determine if a record got inserted.
You can use the following:
sql = "insert into [TableA]..."
Dim recordsAffected As Long
CurrentProject.Connection.Execute sql, recordsAffected
If recordsAffected <> 0 Then
DoCmd.OpenReport(...)
Else
'Nothing got inserted
End If
Or, if you don't like the extra variable, you can consider using a helper function:
Public Function ADOExecute(Query As String) As Long
CurrentProject.Connection.Execute Query, ADOExecute
End Function
sql = "insert into [TableA]..."
If ADOExecute(sql) <> 0 Then
DoCmd.OpenReport(...)
Else
'Nothing got inserted
End If
Note that I highly recommend using a connection to your SQL Server instead of CurrentProject.Connection, which is an ADO connection to Access.

Related

Return Select Queries Using ADO and Provider = SQLOLEDB

My ultimate goal is to run sql queries against sql-server and capture the returned data in a spreadsheet. The following code roughly reflects my current set-up and it works. The design allows me to read sql codes from text files and submit it to a sql-server. "Sub ExecuteCRUD" submits a first sql script to prepare data and dumps the result into a temp table. "Function loadRecordset" submits a relatively simple select query and captures the returned data in a recordset, which I then use to populate a spreadsheet.
There are a couple "variables" in my setup that could potentially be relevant for discussion.
My 4 set of Sql Codes
The ConnectionString (Part of my vba code)
The rest of my vba codes
a. Dbo.ConnectionString = "Provider=MSDASQL;DRIVER=SQL
Server;SERVER=myserver;UID=id;PWD=password;DATABASE=database;"
b. Dbo.ConnectionString = "Provider=SQLOLEDB;Data
Source=myserver;Initial Catalog=database;User
ID=id;Password=password;"
Initially, all I changed was the connection string. The immediate result was connection string version a works perfectly. Using b version, my setup would fail without any errors from sql-server.
Using Connection string version b, "Sub ExecuteCRUD" (data preparation step) would still work smoothly. I can verify that the temp table is created in tempdb as a result of my first sql script.
"Function loadRecordset" would run through the lines without any errors up to and including "rs.open". (I checked for errors, none whatsoever from the ado connection).
Only subsequent codes, when using the recordset to copy out the data would get an error: "Operation is not allowed when the object is closed."
Through some testing, I narrowed down the issue to the sql codes, sort of.
I have to reiterate here. My initial set of sql codes worked completely fine when using the ODBC provider. Things only went sideways using the OLEDB provider.
Using the OLEDB provider, the "offending" sql code was Use databaseABC. Furthermore, using ado, my setup submits 4 sets of sql codes to the sql server. The first set of sql codes prepares data (creating tables, inserting data, creating index, using while loops to populate data, using recursive ctes, etc). In this first set of sql codes, Use databaseABC was also included, and it would execute successfully. The other 3 set of sql codes submitted were only select queries aimed at obtaining data. When Use databaseABC was included in the select query sql codes, the operation failed without any errors. After I took out the Use databaseABC, everything would run correctly in the OLEDB provider world.
Use databaseABC is not a necessary part of the select queries. Using it saves me the trouble of specifying database names all the time in the join clauses.
At this point, my curiosity is two fold
why Use databaseABC causes failures, specifically only when using OLEDB provider, more specifically only when running select queries.
When the failure occurred, should sql-server or the driver generate any errors? What would be the proper way of checking and verifying that?
Private Dbo As New ADODB.Connection
Private rs As ADODB.Recordset
Public Sub ConnectServer()
If Dbo.State = adStateClosed Then
Dbo.ConnectionString = "Provider=SQLOLEDB;Data Source=*server*;" _
& "Initial Catalog=*database*;User ID=*id*;Password=*pwd*;"
Dbo.Open
End If
End Sub
Public Sub ExecuteCRUD(ByVal Sql As String)
On Error GoTo PANIC
Dbo.Execute Sql
Exit Sub
PANIC:
Debug.Print Err.Descript
Stop
End Sub
Public Function loadRecordset(ByVal Sql As String) As Long
On Error GoTo PANIC
Set rs = New ADODB.Recordset
With rs
.CursorLocation = adUseClient
.CursorType = adOpenStatic
.LockType = adLockReadOnly
.Source = Sql
Set .ActiveConnection = Dbo
End With
rs.Open
loadRecordset = rs.RecordCount
Exit Function
PANIC:
Debug.Print Err.Description
loadRecordset = 0
Stop
End Function

Transfer table from Ms-Access to SQL Server

I don't have much experience with SQL Server, I use it currently to run some simple queries, and I link to SQL tables from Access where I have all my heavy queries. My goal is to run all of my queries in Access daily and then at the end write the finished tables up to SQL where my Access front end will read them (versus keeping them in my Access backend).
I've tried messing around with the code below to try and figure out how to do this, but I'm stuck at the driver and I can't find any references on how to do this with just a single table. Let's call it "PO_STATUS_TBL"
Public Sub ADOtest()
Dim ADOConn As New ADODB.Connection
Dim ADOCom As New ADODB.Command
On Error Resume Next
ADOConn.ConnectionString = "Driver =(SQL Server);DRIVER=SQL Server;SERVER=BUSINESS_BWP;Trusted_Connection=Yes"
ADOConn.Open
Debug.Print ADOConn.State
Dim db As Database
Set db = CurrentDb
'db.Execute "INSERT INTO [ODBC;DRIVER=SQL Server;ENCSQL28\BUSINESS_BWP;DATABASE=CurrentDb].SFTransfersDB ( ID, TO ) SELECT ID,TO FROM SFTransfersDB"
End Sub
I went through this process lately.
For migration you can use this tool by Microsoft. With this tool you can either migrate a table or a query to MS-SQL - or even both. Even with relations.
Simple export with this wizard and add your one table through ODBC Connector in Access. Important is to have the correct ODBC Driver.
If you are interested I resolved this issue with Parfait's advise. By using a simple INSERT statement.
INSERT INTO Dbo_PO_STATUS_ALL_TBL Select * FROM PO_STATUS_ALL_TBL

Get Connection string for Pass through queries

I have just learned about the pass through queries in MS-ACCESS.
I have a SQL SERVER backend and
if I'm right, for a query access loads all records before to do the where clause... so what would be the point of having a SQL SERVER backend?
That's why I want to try using pass through queries as much as possible but is there a way I can get the connection string from my linked tables for my pass through queries?
I tried CurrentDb.TableDefs("One of my table name").Connect in the ODBC Connect Str property but I got the error saying it's an invalid connection string.
It would be nice because I know I will have to change the connection soon so I wouldn't have to edit the connection string at many places.
Thank you.
I'm not sure what you meant here: "for a query access loads all records before to do the where clause"
If the WHERE clause can be applied at the server, ODBC will translate it to the server's language, and only the matching rows will be sent back to Access:
WHERE date_field >= #2011-01-01# AND date_field < #2012-01-01#
That WHERE clause would limit the rows sent to Access to only those whose date_field values are from 2011.
However, if a WHERE clause includes functions which must be evaluated by Access, ODBC must retrieve all candidate rows and hand them over to the Access db engine so it can perform the evaluation.
WHERE Format(date_field, 'yyyy') = '2011'
But for your actual question ... connection string for pass through queries ... consider the following code example. I have an ODBC link named dbo_foo whose source table in SQL Server is [dbo].[foo]. So I can grab the .Connect property from dbo_foo and use it for the .Connect property of a pass through query based on the same server table.
Public Sub CreatePassThruQuery()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strConnect As String
Set db = CurrentDb
strConnect = db.TableDefs("dbo_foo").Connect
Set qdf = db.CreateQueryDef("qryDbo_Foo")
qdf.Connect = strConnect
qdf.SQL = "SELECT * FROM [dbo].[foo];"
qdf.Close
Set qdf = Nothing
Set db = Nothing
End Sub
Still when you change the .Connect property of the table, you will also need to do it for the query. If you have many of them and/or change the connections frequently, it may be worth the effort to create a VBA procedure to update them. Alternatively, you might use a DSN for the .Connect property of the table and matching query. Then revise the DSN as needed. A pitfall with that approach is that, if other people will be using your application, you would need to manage the DSNs on multiple machines.

Export multiple queries to different tables

I need to export; Multiple queries to different tables of ms access database from ms sql.
I know it is possible by taking each query and export it to a single table and repeating the same for different queries.
What I want to know is... can it be done in one stretch?
suppose there are three queries and each query output need to be in different tables ... in that case is it possible to do with a single export?
You can save the individual exports as SSIS packages, then combine them into a single package.
The exports might even be able to run in parallel.
I'm not sure what you mean. You could put all the SQL statements into one command batch rather than executing each one separately, e.g:
insert into Table1 select ...
insert into Table2 select ...
insert into Table3 select ...
Are these passthrough queries or Jet (Access) queries? If they are Jet queries, you should create make table queries and run them as a batch through VBA. The make table queries themselves can be constructed easily enough in VBA, if you prefer. Here is an example that gets the connect string from a linked SQL Server table, but you can fill in your own connection string, it should have the same format as the connect property of a linked table.
Dim db As Database
Dim strSQL As String
Dim strConnect As String
Set db = CurrentDb
strConnect = db.TableDefs("dbo_test").Connect
strSQL = "INSERT INTO NewAccessTable (ID, Descr) " _
& "SELECT ID, Descr FROM [" & strConnect & "].[test] "
db.Execute strSQL, dbFailOnError
Debug.Print db.RecordsAffected

Using Select Statement from 1 database to insert into another database using VB .NET

I am currently writing a VB .NET application where I am trying to open 1 database, create a select statement and then post the results into another database file using Microsoft Access database 2003.
The code seems to stop executing at the statement cmdJetDB.ExecuteNonQuery()
I am using the following code:
Dim conn1 As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data source=C:\Sample.mdb")
Dim conn2 As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data source=C:\db2.mdb")
conn1.Open()
conn2.Open()
Dim mySelectQuery As String
mySelectQuery = "SELECT Sample.LANE_ADDR, Sample.LANE_DT, Sample.LANE_TM, Sample.LANE_SPEED FROM (Sample) WHERE ((Sample.LANE_ADDR) = '164.909' OR (Sample.LANE_ADDR) = '164.909' AND Sample.LANE_DT BETWEEN #4/4/2003# AND #4/5/2003#)"
Dim cmdJetDB As New OleDbCommand(mySelectQuery, conn1)
cmdJetDB.ExecuteNonQuery()
Dim cmdInsert As String
cmdInsert = "Insert INTO Table1 (Sample.LANE_ADDR, Sample.LANE_TM,Sample.LANE_SPEED) VALUES ('164.909', '00:12:30' , '30' )"
Dim cmdJetDB2 As New OleDbCommand(cmdInsert, conn2)
cmdJetDB2.ExecuteNonQuery()
conn2.Close()
conn1.Close()
Question: What is it that I am not doing. I opened both connections, stated my two SQL statements, yet it is still not working. I really need to get this application working. Please Help.........
ExecuteNonQuery cannot be used to SELECT stuff from a database. You should use ExecuteReader and use the result in a loop to set the parameters of the INSERT statement and then run ExecuteNonQuery in that loop. From the code you've written, how you'd expect the values should be populated in the INSERT statement?
Here is a sugestion,
If the columns you are retriving have the same type as the columns you are inserting (Basicaly you are not making any conversion and/or transformations) do a single query that does this.
INSERT INTO TestTable2
SELECT * FROM TestTable1
You're using SELECT to try to return rows, but then calling ExecuteNonQuery(), which returns nothing. You'll want to use ExecuteReader() instead.
You'll probably get another error later because you're INSERTing into "Table1" but trying to reference fields in "Sample".
Also unrelated to the error, but you aren't doing anything with the data in the SELECT statement to use it in the INSERT statement.

Resources