SQL Server migrate new data into old schema - sql-server

I have converted MS Access tables and queries to SQL Server tables and views and linked them back to Access. While I was doing this migration, people were using the old Access frontend not linked to SQL Server. Now, the data that I have in SQL Server is the old data when I started the migration. I have created tables, indexes, queries etc in my SQL Server which uses the old data.
Now, I want to deploy the SQL database and link it to Access. Is there a way for me to delete my old data and migrate the new data to SQL Server database while preserving all the schema?
Edit 1:

If you did the migration using SSMA (Sql migration assistant for Access) then you can simply re-run that saved project.
The first time you run SSMA, it will create the data tables on sql server, and then transfer the data.
However, you can open that same SSMA project again, and re-run it, will give you the option to delete the data on SQL server, and send up the existing Access data again.
One of the “really” great features of SSMA is it lets you re-send the data. So you can slice and dice, and try the migration MANY MANY times.
Once you get the migration going the way you want, you migrate the data. You then work on getting your front end to work with sql server. During this time, no doubt users are still using the older system (non sql server).
For example, SSMA allows you to add a PK to each table (if it does not have one). I often found a “few” tables such as for driving combo boxes etc. does not (did not) have a PK for that table that say drives a combo box. So during the migration, you want to let SSMA create the PK for you. You can do this manually after the migration, but then you need to write down some “cheat” notes, since as you point out, you going to have to do the migration again later on.
So, if you make any “manual” changes to the data structures, then you want to “save” those changes in the event that you migrate again. The beauty of this, is WHEN you in the table design mode (sql server), you can right click, and choose “script” changes. So if you make say 10 or more changes to each table, you can save your changes into a sql script. So now you can migrate, and then run those scripts.
Now, after the migration, you get to work making this front end work with SQL server. During this time no doubt users are STILL working on the old system (access back end).
Once your new front end is working fine with sql server, then you pick a day for the new roll out. You after work, or during down time, re-run the SSMA project you saved. The result is now SQL server has the most up to date data. And then you are now able to roll out and deploy out the new front end that is linked to SQL server.
As noted, while SSMA can migrate Access queries, I VERY strong recommend you don’t do this. Just migrate the data, and link the front end tables to sql server. At this point, 99% of your Access appcation will work as before. You “may” have to change the VBA open recordset commands (to add dbOpenDynaset, and dbSeeChageesto that openRecordSet command (but that is a global search and replace – not much time at all).
So you likely have lots of code like this:
Set rst = CurrentDb.OpenRecordset(strSQL)
And you need to change above to:
Set rst = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)
The above will thus allow 99% of your VBA reocrdset code to work as before without changes.
The only “common” got ya, is with a Access back end, the autonumber ID is generated INSTANT as a you dirty a form, or dirtry (add too) a record. This allows code to grab the auto number PK right away.
So such old code as:
Set rstRecords = CurrentDb.OpenRecordset("tblmain")
rstRecords.AddNew
' lots of some "code" here follows
lngPK = rst!ID
In above, note how my VBA code grabs the PK auto number.
In sql server, you cannot grab that PK until AFTER you force the record save. And DAO has a VERY nasty issue is that after you issue a update (during add only – I repeat during adding reocrds only!!!), then the record pointer jumps off the current record. This DOES NOT occur when you using DAO recordsets to update a existing record (again: only for new reocdors).
So, so above code now becomes:
Set rstRecords = CurrentDb.OpenRecordset("tblmain")
rstRecords.AddNew
' code can go here to add data, or set values to the reocord
rstRecords.Update
rstRecords.Bookmark = rstRecords.LastModified
lngNext = rstRecords!ID
rstRecords.Close
So, for code that grabs the autonumber PK right away, we have to do two things:
Force a record write (update)
And then after the update, re-positon the record pointer. (you ONLY need this re-postion when adding – not edits, but I often do this anyway). This re-position issue is perhaps my LARGEST pain of using DAO (ADO does not require this re-position).
So your code add/sets the fields etc. in that reocrdset do NOT have to be changes. So leave that code that does whatever the heck the code did before.
Now issue the update, AND THEN GRAB the autonumber PK.
So above should cover 99% of your VBA code you have to change. Even in a rather large project, the above issue will only occur in a few places. (I find that I can search for “.add” in the code base, and rather fast determine if code is grabbing the autonumber PK before the “.update” command is issued.
The same goes for forms. When a user starts typing, the form becomes “dirty”. With Access back end, the autonumber PK can be grabbed by code, but with sql server back end, you have to issue a record save in the form, and THEN grab the PK ID.
So, you add this one line:
If me.Dirty = True then me.Dirty = false
lngID = me!id
So you added the one line to force a record save (me.Dirty = false).
And again I tend to find even with say 150 forms, only 1 or 2 will do this “grabbing” of PK id before the forms record has been saved. So this “lack” of autonumber being able to grabbed for new records will occur for both forms, and VBA reocordset code. Few forms do grab the PK autonumber ID, but some do need this (say to add child records). However, existing forms + sub forms do NOT have this issue, since access ALWAYS issues a record save when the focus jumps from the main for to any sub form.
Anyway, once you get the new front end working (and of course one linked the front end using the same table names as before).
If I recall, SSMA tends to put “dbo” in front of the Access table link names – you don’t want that. The dbo schema on sql server side is the default, and again that should not pose any issues or problems.
So yes, SSMA allows you to re-run the migration, and it allows you to delete your data on SQL server during that re-migration. You not need to delete the old data, SSMA can do this for you.

Related

Insert Data From Access Database to SQL Server

Desired result and why:
I have a lot of old Access databases that we are trying to get to SQL Server, and I'm essentially trying to make the Access DB the "middleman" so our old programs can still read/write to them but the information will also be saved in SQL Server. We need the middleman because of how interconnected these tables are through various programs we are rewriting in modern languages. Once we rewrite all of them we will cut the cord and live in SQL Server, but this will take a lot of time.
What I've tried:
We tried creating a linked table to SQL Server and renaming it so it would take the place of the original table. After doing this the table stopped receiving data so we quickly reverted back.
In order to investigate this I created Table B which is just another linked table to SQL Server, and then tried using the After Insert macro on Table A to send any new rows to the linked table but nothing happens. If I manually add a record to Table B it carries over to SQL Server just fine, but I can't get Table A to send data to Table B. I created Table C that is just a local access table and if I manually add a record to Table A it does show up in Table C. No errors at all, it just doesn't do what I need it to do.
I'm lost on how to accomplish this and open to any help or suggestions on how to move forward with this. One thing to note though, is that most of the access databases I have are not using forms at all which is I'm trying to take the macro route instead of any VBA. I need these to trigger without any interaction from the user.
You should use the tool dedicated to this task:
SQL Server Migration Assistant for Access (AccessToSQL)
Ok, there are from comments some new and signficant moving parts here.
For example, data is to be migrated to sql server. As noted, EVEN in access land, all and every table needs and should have a PK for the "basic" data base operations. While it is possible to do some work, and say some importing of data, the instant one wants some forms, VBA code and starts to build a working applcation? Then all tables should have a PK.
And of course if you moved the data to sql server, then it not going to make a lot of sense to have OTHER applcations attempt to modify the linked tables in access, since the data is not in Access anymore!!! Those other sources in theory should thus also hit sql server, and not attempt to use what amounts to a link on a linked table.
However, it does depend. For example, if you use vb.net code and say open a access database, you CAN in fact have that vb.net code open a access table, and in fact it can be a linked table. (however, it would make a WHOLE lot more sense for the vb.net code to open and hit sql server - introduction of a link on a link is going to be problematic.
However, in testing, I have found that say vb.net can open a access table, and even if it is a link, then access will translate though the jet engine (the access data engine), and you can do this.
However, data macros and table triggers on existing access tables? They might work on linked tables, but you of course need to ensure that the linked table does allow edits, and allows inserts. Only AFTER one has verified that you can click on a linked table to sql server - can edit, and then add should one mess around with data macros and triggers on say local tables.
it also depends on what the new software tools and platform is being used here.
But, from a basic database point of view - and general data mangement?
All code, and designs should assume, and be designed around the assumption that each row of data has a PK. This is not always possible, but is a RARE use case.
Practical data management - and use of a database should from both table designs, and from workflow designs, and from a developer point of view assume the concept of a PK row id. Without such assumptions, then you not in the software industry anymore - but in a hack field, and one that will result in great future difficulty when attempting to build work flows and build general information systems.
So, with above in mind: Your table B - it has to work as a valid sql server table.
The sql server table(s). They need a PK, and after linking to sql server, you can open up the linked table in access. Test if edits work, test if adding works, and even perhaps test if delete works. Only AFTER such time, do you now want to start testing any code or other operations from the Access client side.
Introduction of using a linked table from another application? That is a foggy area, but I can confirm for example that say .net oleDB provider will and can open a access database and use + consume even linked tables.
You also don't mention if you using sql logon, or windows auth for the sql server linked tables. But if you using sql logons, then when linking a table, you see this check box - and you want to ensure you selected this when linking the table(s) in question:
Note that you ONLY get this prompt on the first time create of the table link - additional use of the linked table manager (such as re-fresh links) does not offer this prompt. If you don't select the save password option, then you often see a sql logon prompt when you attempt to open a linked table in access.

Cannot edit one record on linked table write conflict

We have a linked table in our Access 2010 database, the backend is SQL Server 2012, via an ODBC connection. The table is indexed (unique, non clustered) on a single field, the record's identifier.
The issue is that the odd record throws a 'write conflict - record changed by another user' type error when it is edited through the Access front end, but can be edited directly in SQL. Other records are fine. It's not the same record each day. The whole situation is a complete mystery to me so here are all the fact, maybe someone can make a coherent picture out of this.
The error message takes two different forms, depending how the edit is attempted. The normal functioning of the front end does it by opening a DAO recordset with just the one record, doing a bunch of edits on different fields, then closing the recordset and setting all object variables back to nothing. That produces first the "Write Conflict - This record has been changed by another user since you started editing it." error, with "Drop changes" or "Copy To Clipboard" as the options." It is then followed up with error 3197 "The Microsoft Access database engine stopped the process because you and another user attempted to change the same data at the same time."
If I just open the table in Access and manually try to change the record, I get the write conflict version of the error only. (Needless to say, I have confirmed that no other users are in the table at all, let alone the record.)
I can edit the row in SQL, and I can edit the row using a query in Access (via query design).
The data in the table is built each morning, and each day it seems to be a different record or two that is affected. It has only gone on for a few weeks, in a setup that has been running fine for about 6 months with no changes that could account for this (at least, that I can think of). The data build truncates the table and inserts all the records from scratch, and then rebuilds the index.
Here are some things I've tried:
Decompiling the database, compact and repair, relinking the table.
Linking the table into a brand new database that only has that one table in it.
Rebuilding the index.
Deleting the row and re-inserting it
Rebooting the SQL server (that was due to something else, but the problem still continued afterward.)
Opening the front end on a different computer.
Any help would be much appreciated!

Maintain SQL Server scripts

Our firm does not have a dedicated DBA employed but does have select developers performing DBA functions. We update our database often during a development cycle and have a release script with the various updates. We keep our db schema and objects in Visual Studio in a Database Project.
However, we often encounter two stumbling block problems that causes time-intensive manual intervention:
Developers cannot always sync from the Database Project to their local database because if we have added a NOT NULL field to an existing table that contains data then the Deploy process for VS to the db isn't smart enough to automagically insert "test" data just get the field into the table (unless this is a setting someplace?). We would of course follow this up, if possible, with a script to populate the field with real data, but we can't because the deployment fails.
Sometimes a developer will restore a backup from any past random date. There is no way of knowing exactly which db updates were applied to this database, so they don't know which scripts to start applying. What we do in this case is to check each script, chronologically, to see if the changes from that script have been applied to the database. If so, move on to the next script to run. Repeat.
One method we have discussed is potentially creating a "Database Update Level" table in the database with 1 field, 1 row. It would maintain the level that the database has been updated through. For example, when the first script is run, update the level to 2. In each db script, we would wrap the statements in a check such as
IF Database_Update_Level < 2 THEN
do some things here
UPDATE Database_Update_Level SET Database_Update_Level = 2
END IF
The db scripts can then be run on any database because the individual statement won't execute below a certain level.
This feels like we're missing something because this must be a common problem that every development shop that allows developers to develop locally encounters.
Any insights would be greatly appreciated.
Thanks.
about the restore problem, I don't see many solutions, you might try to prevent full restore and run scripts to populate the tables instead. As for versioning structures, do you use SSDT (SQL Server Data Tools) in VS ? You can generate DACPACs and generate diff scripts.
But what you say is that you also alter structures directly in the database ? No way to avoid that ? If not you could for example use DDL triggers (http://www.mssqltips.com/sqlservertip/2085/sql-server-ddl-triggers-to-track-all-database-changes/) to at least get notified that something changed.
One easy way to solve the NOT NULL problem is to establish default constraints (could just be an empty string, max number value for the data type, max date value, etc.). When the publish occurs the new column will be populated with the default value.
For the second issue I'd utilize post-deploy scripts in your SSDT project to keep the data in sync utilizing 'NOT EXISTS' to make incremental changes. That way, you can simply publish the database and allow the data updates to occur one after another.

Oracle SQL Developer DDL working on more than one schema at once

I am new to Oracle SQL Developer (about 1 month of use), having always used Toad. I have 2 almost identical schema set up - one to test older code, one to develop a modified versions. I have 2 different connections set up - one to each schema, with separate user names for each one.
But when I delete a table or column from the schema in one connection, it is also deleted or changed in the other.
This happens if I right-click on the table or field in the Connection explorer panel, or if I open a SQL Script saved to disk. If I open a SQL script, I even see a pop-up that asks me what connection to use, but if I select one, it still makes changes to both. Even if I only have one of the two connections open, the script will still change design in both of the connections.
The only way I can be sure to make changes to just one of the two is to right-click on the connection name in the Explorer panel, and open a new SQL Worksheet. The worksheet is then named for the connection and just makes changes to it.
This is not the behavior I was expecting, and I'm facing many hours of work to get the definitions of the 2 schema back to where I need them to be. I am wondering if there is some key concept or distinction I am missing or if there is some way the database(s) are set up that is enabling this to happen.
In case you never found the answer for your question. This is my understanding:
The database may have several schemas. The schema is not a separate database, it is a grouping of objects in that database. If you change something while in one schema, you are really changing it in the database, not just the schema. I hope this helps.
Are you just trying to test things in one schema? It sounds like you may want to have a Database and a TEST Database. You could test whatever you wanted in the TEST database and never have it change the real database.

How to create reports in Access via ADO When data is in SQL Server?

I have an Access 2003 project in which all data is stored in SQL Server 2008. I am using ADO to view/update data via forms that are completely unbound. For example, a form has several textboxes and combo boxes on it. When the form is loaded I use ADO to make a call to a stored procedure on SQL SQL, it returns a recordset and I populate the controls, via VBA, with the data from the recordset. I like this approach because only the VBA is stored within Access. No data (well actually connection strings are stored in Access, but that is it!).
My problem is what to do when it comes to reports. I want to create reports that are based off of views created within SQL Server, however I would like to avoid, if possible, static linking to the views directly from within Access. Is it possible to set the recordsource of a report dynamically at run-time to be the results of a SQL Server view? If it is, how does one go about designing the report id Access does not contain any data?
More info ... The reason I want to avoid linking to the view in Access is the environment in which the Access application could be run changes (Production, Development, Test). Currently whenever I make any calls to the database stored procedures, I look up the connection string (Active Directory based so no passwords are stored) in the only table that is stored in Access .
Thanks for any assistance.
First of all let's be clear: you don't have an Access 2003 "project." You have an Access 2003 database.
An actual Access Data Project cannot have local tables, and uses a SQL Server as the back end. When you view Tables you see the ones that exist on the server, and under Queries you see the views, functions, and stored procedures that exist on the server. You can use the "Upsize Wizard" to turn an Access database into an Access data project (or probably better, just create a new ADP (Access Data Project) and import all the forms, reports, macros, and modules.
Here are my ideas:
Convert the database to an actual Access Data Project and then just use regular old queries as if they were addressed to the local database. You can even bind forms to stored procedures and they can be updatable. To deal with Production, Development, and Test, you just change the connection string in the GUI or you change it through code like so:
Application.CurrentProject.CloseConnection
Application.CurrentProject.OpenConnection NewConnString
If you want to read the connection string from a centralized database or from a text file on a share or from a common table you load in each environment (that has the connection information for every other environment), that is up to. I have one Access Data Project that has an toolbar with an Environment dropdown. When the environment is switched, a child database dropdown is then populated, and finally all open forms are notified by an event (though bound forms close when this occurs).
There's nothing wrong with using linked tables. Just write a procedure that loops through all the tables and updates them to point to the correct server when you want to change environments. The difference between "static" linking and "dynamic" linking is just a single VB procedure that rips through all the tables and relinks them--easy peasy.
Setting a report recordset dynamically at runtime is problematic. It MIGHT be possible in actual Access Data Projects, but definitely not in regular MDBs.
You CAN create pass-through queries in an Access MDB, but I'm not sure about passing parameters in. You'd probably have to set the query text dynamically with the parameters hard-coded and then run the report. This would be a problem for a multi-user database unless each person gets his own front-end to run from.
I recommend that you go with option 1 or 2. Option 1 seems simplest but there is some learning to do before you'll become facile with ADPs over MDBs. Let me know if you think you'll go down that route and I I'll share some of the gotchas with you. However, it's probably easier than what you're doing now which is everything manually. (Ouch!) The second option would be fastest for implementing right away and not throwing any wrenches into your current skill with MDBs.
UPDATE
So if you want to link tables, here's some code to get you started:
Sub TableRelink(MdbPath As String)
Dim Table As DAO.TableDef
Dim Tables As DAO.TableDefs
Set Tables = CurrentDb.TableDefs
For Each Table In Tables
If Table.SourceTableName <> "" Then 'If a linked table
Table.Connect = ";DATABASE=" & MdbPath 'Set the new source
Table.RefreshLink
End If
Next
End Sub
This code is for MDB files, but some digging will quickly give you the correct properties and values to use for SQL Server linked tables.
Another Thought
I just thought of another possible way to handle just the problem you're experiencing: Use a session-keyed "temp" table in Access. Create a local table that has all the columns the view returns, plus a GUID column. When the report is run, insert the contents of the view to the local table, keyed by a new GUID value. Set the recordsource of the report to SELECT * FROM MyViewTempTable WHERE GUID = '{GUID}'. Simple problem solved. On report_close, delete from the table. Perhaps put in a date also and delete after 10 days in case any rows get left behind.

Resources