I get error 3035: 'System Resource Exceeded' when executing the following sub:
Private Sub delete_result_staging()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb
Set qdf = db.QueryDefs("qryWQPassthrough")
qdf.Connect = Me.con_str.Value
qdf.ReturnsRecords = False
qdf.SQL = "TRUNCATE TABLE tblWQResultStaging;"
qdf.Execute
Set qdf = Nothing
Set db = Nothing
End Sub
I am using MS Access 2013 and SQL Server 2012.
This code has worked previously; it stopped working when I refactored another sub per How to increase performance for bulk INSERTs to ODBC linked tables in Access?. I have changed the MaxLocksPerFile to 1,000,000 in the registry per other suggestions on the internet. I restarted Access and my computer, and I still get the error every time the sub fires. In the SQL Server Profiler I see no activity on the server when the code is executed. Forms and reports that point to linked tables on the same server but are connected via the GUI, rather than through VBA, still work as expected.
I figured out the issue was that I was reusing a single passthrough query multiple times in VBA. It didn't like the SQL statement that was in the query from the last time I used it in code, so it threw the error. Looks like I need to either be more careful with my earlier VBA code that uses that query, or use separate queries for every VBA sub, or both.
Related
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
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
I would like to have an Access VBA sub that sends an instruction to a SQL Server database to copy some data from one of the remote tables to another table (at least one of the tables is not linked to the local Access database). I want this to all happen on the server, as this is a lot of data.
I'm trying something like the following, but it returns an run-time error 3065 (Cannot execute a select query). Any insight into how to fix? Is there some reason I couldn't do this from Access?
Also, I'm using a DAO approach, but is there a better approach (ADO?)? Somewhat new to this so not always sure I understand the nuances of the different approaches.
Public Sub myTest()
Setup:
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb()
Set qdf = dbs.CreateQueryDef("")
qdf.SQL = "INSERT INTO tmp SELECT [Applicant], [CaseName], [DecisionDate], [Filed], [Docket] " _
& "FROM Cases WHERE [DecisionDate] >= '01/01/2018';"
qdf.Connect = "ODBC;Driver={SQL Server};server=myServer;database=myDB;"
qdf.Execute
End Sub
What you have looks ok. I would “test” the sql first by running the exact same command by using SQL management studio.
As for your code? It also looks ok, but I find it MUCH better to save a PT query and thus you don’t have to mess with the connection string in code. And thus your code becomes:
With CurrentDB.querydefs("MyPassR")
.SQL = "INSERT INTO tmp SELECT [Applicant], [CaseName], [DecisionDate], [Filed], [Docket] " & _
"FROM Cases WHERE [DecisionDate] >= '01/01/2018';"
.ReturnsRecords = False
.Execute
End With
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.
I have a stored procedure which when run from SQL Server Management Studio consistently takes 5 seconds to run when called like this.
exec dbo.MyStoredProc '2009-04-30 00:00:00', '2009-04-30 20:00:00'
When called from an excel spreadsheet via VBA it takes 6 minutes plus (not including the time taken to copy the recordset to a sheet. The VBA is nothing fancy simply using an ADO connection to return a recordset. Unfortunately the Excel approach is a client requirement that I can't get rid of yet.
Public Function GenerateSQL(strQueryName As String) As Recordset
Dim rs As Recordset, cm As Command, dbsConn As Connection
Set dbsConn = New ADODB.Connection
dbsConn.Open Configuration.Range("ConnectionString")
Set cm = New ADODB.Command
With cm
.CommandText = strQueryName
.CommandType = adCmdStoredProc
.CommandTimeout = 300
.ActiveConnection = dbsConn
Set rs = .Execute()
End With
Set GenerateSQL = rs
End Function
Does anyone have any idea why this would happen or how I could begin to trace what is happening?
Thanks,
Steve
Everything you need to know about this topic: Slow in the Application, Fast in SSMS? Understanding Performance Mysteries
I believe I have the same problem as Steve Homer.
In addition to this SO question I also found this thread on eggheadcafe.com Very slow SP execution when using .net - very fast in Management Studio - totico
The answers say it's about parameter sniffing and how that affects which execution plan is used. The answers there specifically mentions the arithabort set option and how that affects the selection of plan.
Now I just need to find out how to change the set options from VBA...
Finally thanks to this forum entry on social.msdn.com i managed to get it right. First, set multiple connections to false:
connectionObject.Properties("Multiple Connections") = False
and then use the following function on your connection to set arithabort on ...
Private Sub OptionSet(ByRef cnn As adodb.Connection)
Dim cmd As adodb.Command
Set cmd = New adodb.Command
With cmd
Set .ActiveConnection = cnn
.CommandType = adodb.CommandTypeEnum.adCmdText
.CommandText = "set arithabort on"
Call .Execute
End With
Set cmd = Nothing
End Sub
Use SQL Server Profiler
Set up a trace on your database.
Limit the trace only to the stored procedure object in question
Limit to the username used by the VBA code
An introduction to SQL Server Profiler
In particular, check the SET options used by the connection and compare these with the defaults used when running the stored procedure in SSMS.
I have come across scenarios before where the SET options were different between calling code and within SSMS and the difference in performance was HUGE.
Thanks I'll take a look at the trace tools.
In reply to the comments on the original question
Are you using the exact same parameter values?
Yes exactly the same.
How much data is being returned (roughly) - number of rows and columns (and are any of them particularly big)?
Under 200 rows, perhaps 15 fields mostly ints with a couple of 20 character varchars.
Can you run SQL profiler and confirm if the sql is the issue or the remains of the macro in excel ?
The SQL is pretty ugly, as is the underlying database schema, and unfortunately is under NDA so I can't post it. If the query were the issue then wouldn't it be slow in management studio too though?