I am converting an Access 2010 database from using DAO in the native database to using SQL Server 2012 accessed by ADO. Everything has gone flawlessly without too many code changes... except for one thing:
I have some very simple temp tables in which I need to delete all the rows before using. There are no joins or constraints on the table -- just three columns, all of which are part of the primary key.
This is the old DAO code which worked in the MDB:
DoCmd.SetWarnings False
DoCmd.RunSQL ("DELETE * FROM Print_Tickets_TEMP;")
DoCmd.SetWarnings True
This is the new ADO code which produces an error in SQL Server:
CurrentProject.Connection.Execute "DELETE FROM Print_Tickets_TEMP;"
Running this ADO code produces an error:
Could not delete from specified tables (err 80004005).
It's obviously pretty basic stuff which works in SSMS and in an Access pass-through query. So, I thinking there must be some sort of permission, locking or property that I'm not setting. Note that Connection.Execute gets used all over the app with INSERTS and UPDATES.
The only info I found when searching for answers related to issues people had deleting from joined tables. As I noted, this is a simple standalone table. Anyway, I'm at my wits end... if anyone has any ideas on what's missing or can explain why I can't/shouldn't be doing this, that would be greatly helpful!
edit: If it helps, this code is in a VBA module being called from an Access form.
If there is a specific stored procedure causing this problem, try adding these lines to the beginning of the proc.
SET NO_BROWSETABLE OFF
SET NOCOUNT ON
If you are querying system tables, use a forward-only cursor (to be safest, avoid ADODB.Recordset altogether).
If you are using SQL Server 7.0: if you have ANSI_WARNINGS set to OFF, see KB #259775; if you are using the ROUND() function, make sure that the parameters you are sending are not null (see KB #199105)
If you are using SQL Server 2000, and are using SELECT DISTINCT on a table with a LEFT JOIN on a view, upgrade to SQL Server 2000 Service Pack 2 (see KB #308547).
If you are using MTS transactions, try to change your approach by using transactions within SQL Server.
If none of the above solves your issue, see KB #243899.
http://tutorials.aspfaq.com/8000xxxxx-errors/80004005-errors.html
Related
I need a bit advice how to solve the following task:
I got a source system based on IBM DB2 (IBMDA400) which has a lot of tables that changes rapidly and daily in structure. I must load specified tables from the DB2 into a MSSQL 2008 R2 Server. Therefore i thought using SSIS is the best choice.
My first attempt was just to add both datasources, drop all tables in MSSQL and recreate them with a "Select * Into #Table From #Table". But I was not able to get this working because I could not connect both OLEDB Connections. I also tried this with an Openrowset statement but the SQL Server does not allow that for security reasons and I am not allowed to change that.
My second try was to manually read the tables from the source and drop and recreate the tables with a for each loop and then load the data via the Data Flow Task. But I got stuck on getting the meta data from the Execute SQL Task... so i dont got the column names and types.
I can not believe that this is too hard to archieve. Why is there no "create table if not exist" checkbox on the Data Flow Task?
Of course i searched for the problem here before but could not find a solution.
Thanks in advance,
Pad
This is the solution i got at the end:
Create a File/Table which is used for selection of the source tables.
Important: Create a linked Server on your SQL Instance or a working Connectionstring for the OPENROWSET (i was not able to do so - i choosed the linked server)
Query source File/Table
Build a loop through the resultset
Use Variables and Script Task to build your query
Drop the destination table
Build another Querystring with INSERT INTO TABLE FROM OPENROWSET (or if you used linked Server OPENQUERY)
Execute this Statement
Done.
As i said above i am not quite happy with this but for now it should be ok. I will update this if i got another solution.
I am working on a project that will use MS Access as front end and SQL Server for data storage. I don't want to link the tables directly because I don't want to take the speed hit to the front end from the 'live' updates. I can't reference the Access DB through JET etc because it is not based in a fixed location so I can't pass through and run directly from server end
I've got as far as this (vba in access):
Sub inserttoaccess()
strSQL = "insert into AccessTable SELECT * FROM [myserverconnectionstring;].servertable"
CurrentDb.Execute (strSQL), dbFailOnError
End Sub
Sub inserttoserver()
strSQL = "insert into [myserverconnectionstring;].servertable SELECT * FROM AccessTable"
CurrentDb.Execute (strSQL), dbFailOnError
End Sub
Which works, and hopefully demonstrates what I need to do, but I'm looking for a way to do it which doesn't require me to keep referring back to the connection in every query. Maybe a way to link to the server without linking specific tables or a function that I could hardcode the connection string but pass the query, but not sure how that would work...
This is the first time I've been looking at using MS Access and SQL Server together so looking for some input as to how those more experienced approach this please
This Post, answered by HansUp (Sorry not enough rep for an upvote)
specifically this:
INSERT INTO MyNewTable (fld1, fld2)
SELECT first_field, second_field FROM YourPassThruQuery;
provides a possible solution without linked tables
Rather than the approach I was trying to take of inserting to an access table from a sqlserver table I can insert to an access table from an access pass through query
By having the connection string in a couple of pass through queries that relate to all the data I need from the server I can then reference these in the multitude of sub queries relating to user input without having the connection string in each one
The question of whether this is method that should be used for this problem stands, but this seems like a viable solution, or at least compromise to limit the number of connection references
Edit: By combining the above with this and hardcoding the connection string I should be able to only reference the connection once, provided the SQL server tables are all on the same database
Sadly (for some) ADPs are out. ADO is out too.
The current recommendation for Access/SQL Server desktop applications is linked tables and queries over DAO using the SQL Server Native Client, version 11.0 or later. Starting with Access 2013, Microsoft has done a lot of work to make this arrangement perform well with SQL Server and Azure.
As for your question in the comments, whether you need to synchronize local Access tables with remote SQL ones depends on what the application is supposed to do:
If the user expects to be able to work while disconnected from the
network/internet/cloud, then you need to synchronize local tables
But, if you are doing a standard application, where persistent links
to the SQL data are assumed, then just do all of your reads and
writes against linked SQL tables. Use pass-through queries to call stored procedures and functions.
At the risk of starting an ODBC/OLEDB arguement, does anyone have any best practice suggestions for linking an Access Front End to a SQL Server Backend?
I have read the articles about .ADP vs .MDB and have also been through the DNS-less connections information and agree with the thinking.
My main question is around linking the data and performance. In the past I have found forms to be slow when connected directly to the SQL database, I have tested forms based on ODBC linked tables vs an OLEDB connection in the 'OnOpen' event and found the OLEDB approach to be quicker although not great. Therefore I have implemented routines where the data is copied locally when opening a form, modified, then written back to the database when complete but this has its own problems.
Does anyone have suggestions on the best practice approach for this kind of setup? Am I missing something that will improve my forms that are linked directly to the SQL Server?
Any comments or hints appreciated.
You must reduce network traffic to a minimum, especially acknowledgement exchanges. Do this by running SQL exclusively on the SQL server as much as possible, transmitting only complete rowsets back to the client. At all costs avoid joining data on the server to data in the Access DB. That should get you started.
The basic approach is to simply use linked tables.
You should not be seeing any real difference here when using ODBC. ODBC is the preferred approach and Microsoft has announced the end of oleDB support (and the .net community left oleDB and ADO about 10 years ago).
You can bind a form to these linked tables and achieve good performance. The simply trick is to reduce and limit records pulled. This limiting can be accomplished by using a SIMPLE where clause when you launch those bound forms.
So, if you launch a bound invoice form and supply the where clause on the standard open form command then ONLY the one record is pulled. And if course if you have a bound sub form then only the correct records will be pulled from the server also. So no advantage here by using oleDB or ADO will exist in 99% of your cases.
So as a general development approach you can in most cases you can use bound forms.
Where caution is required is that for some joins and anything with aggregate queries, then you want to use a linked table to a sql view. You can also consider using pass-through for reports, but pass-through tends to be more work, and a linked view means you can keep your existing VBA code that likely (hopefully) used a "where" clause to open those reports and again restrict records pulled down the network pipe.
And for dynamic pass-through to execute server side commands, I use this code:
Dim qdfPass As DAO.QueryDef
Set qdfPass = CurrentDb.QueryDefs("MyPass")
qdfPass.SQL = "exec sp_myProc " & "p1"
qdfPass.Execute
If you need the above to return records, then just go:
Dim qdfPass As DAO.QueryDef
Dim rstData As DAO.recordSet
Set qdfPass = CurrentDb.QueryDefs("MyPass")
qdfPass.SQL = "exec sp_myProc " & "p1"
set rstData = qdfPass.OpenRecordSet
So you can on the fly change/modify the above sql for a pass-through query with very little code. At the end of the day, you thus achieve first rate performance, and do so with very few coding changes to the existing application.
So the current recommend approach here is to use DAO. And do keep in mind that end of life support for oleDB (and ADO) for sql server has now been announced. See here:
http://blogs.msdn.com/b/sqlnativeclient/archive/2011/08/29/microsoft-is-aligning-with-odbc-for-native-relational-data-access.aspx
I've used temporary tables before without any trouble, but today, they are not working for me. This returns
. #MyTemp not found
from the last line.
scBld.CommandText = "select top 10 * into #MyTemp from elig_feeds";
scBld.ExecuteNonQuery();
scBld.CommandText = "select count(*) from #MyTemp";
int p = (int) scBld.ExecuteScalar();
If I remove the "#"s, it works fine.
The only thing that has changed recently is version compatibility of the database, but I don't see that would be a factor. The db is 2005 developer edition.
Thx.
I had similar issue today with 2005 Express both using ODBC and OLE DB.
As explained in this article this behavior might be due to using prepared statements, which are wrapped into temporal stored procedures when prepared.
In SQL Server 2005, SQL Server 2000, and SQL Server 7.0, the prepared
statements cannot be used to create temporary objects and cannot
reference system stored procedures that create temporary objects, such
as temporary tables. These procedures must be executed directly.
Supplying statements directly using SQLExecDirect did help to fix the application. Not sure how that should be applied to ADO.NET though.
Check if connection is getting closed automatically. You are executing two different commands, depending on connection settings, it may get reset after you call ExecuteNonQuery().
[Temp tables are destroyed when connection is closed.]
We have a Visual C++ 6 app that stores data in an Access database using DAO. The database classes have been made using the ClassWizard, basing them on CDaoRecordset.
We need to move from Access to SQL Server because some clients have huge (1.5Gb+) databases that are really slow to run reports on (using Crystal Reports and a different app).
We're not too worried about performance on this VC++ app - it is downloading data from data recorders and putting it in the database.
I used the "Microsoft SQL Server Migration Assistant 2008 for Access" to migrate my database from Access into SQL Server - it then linked the tables in the original Access database. If I open the Access database then I can browse the data in the SQL Server database.
I've then tried to use that database with my app and keep running into problems.
I've changed all my recordsets to be dbOpenDynaset instead of dbOpenTable. I also changed the myrecordsetptr->open() calls to be myrecordsetptr->open(dbOpenDynaset, NULL, dbSeeChanges) so that I don't get an exception.
But... I'm now stuck getting an exception 3251 - 'Operation is not supported for this type of object' for one of my tables when I try to set the current index using myrecordsetptr->->SetCurrentIndex(_T("PrimaryKey"));
Are there any tricks to getting the linked tables to work without rewriting all the database access code?
[UPDATE 17/7/09 - thanks for the tips - I'll change all the Seek() references to FindFirst() / FindNext() and update this based on how I go]
Yes, but I don't think you can set/change the index of a linked table in the recordset, so you'll have to change the code accordingly.
For instance: If your code is expecting to set an index & call seek, you'll basically have to rewrite it use the Find method instead.
Why are you using SetCurrentIndex when you have moved your table from Access to SQL Server?
I mean - you are using Access only for linked table.
Also, as per this page - it says that SetCurrentIndex can be used for table type recordset.
In what context are you using the command SetCurrentIndex? If it's a subroutine that uses SEEK you can't use it with linked tables.
Also, it's Jet-only and isn't going to be of any value with a different back end.
I advise against the use of SEEK (even in Access with Jet tables) except for the most unusual situations where you need to jump around a single table thousands of times in a loop. In all other DAO circumstances, you should either be retrieving a limited number of records by using a restrictive WHERE clause (if you're using SEEK to get to a single record), or you should be using .FindFirst/FindNext. Yes, the latter two are proportionally much slower than SEEK, but they are much more portable, and also the absolute performance difference is only going to be relevant if you're doing thousands of them.
Also, if your SEEK is on an ordered field, you can optimize your navigation by checking whether the sought value is greater or lesser than the value of the current record, and choosing .FindPrevious or .FindNext, accordingly (because the DAO recordset Find operations work sequentially through the index).