I'm looking to switch to DACPACs for our database changes, but I'm a bit at a loss about what to do when it comes to more complex database updates. To illustrate what I mean, let me use a simple example that has the same problem.
Say I have a Customer table that is currently live and I want to add a new CustomerType table with a foreign key from Customer to CustomerType. The new column in Customer should be required (not nullable), but should not have a default value.
I want to use some arbitrary formula to setup the initial type for the existing customers upon upgrading. How would I accomplish this using a DACPAC?
The DACPAC will only know there's a new column and will try to add it to the Customer table, which will of course fail because it is required. Setting a default value is undesirable, as is allowing null values.
Since the DACPAC should be usable to upgrade from every state to the latest, I don't see what kind of configuration or pre/post scripts I should setup to make this work.
Various searches have produced a disappointing lack of useful results :(
I hope there's someone here that can help out. Thanks in advance.
The answer will vary a bit depending on how you're planning to deploy the dacpac(s). One common case is having the dacpac replace some collection of T-SQL update scripts that are executed in sequence to update a database schema from one version to the next. In this case you might choose to have one dacpac file for each schema-version of your database and to update a database you would plan to publish the dacpacs in sequence to update a database to the latest version.
In that case, it's possible to use a post-deploy script to fix up the schema as appropriate. For your example scenario, you can model the database in the database project with the new column specified as NULL and without the FK relationship with the new table. Then, in a post-deploy script you can author the T-SQL necessary to execute an UPDATE statement to fill the new table and the new column, an ALTER statement to change the column's type from NULL to NOT NULL, and finally to add the foreign key relationship.
Then moving forward you can remove the post-deploy script and model the new column and table with the proper column type and FK relationship.
Related
I have an existing database in MS SQL server and want to rename some tables and columns because the names currently used aren't accurate to what it represents.
I have multiple web and desktop applications that access the database, using Entity Framework (code first). Too many to update in one go and cannot afford for all apps to start working.
I was thinking it was nice is SQL server allowed a 'permanent' alias for tables and columns but I don't think this feature exists.
Or I was wondering if there was a way in EF to have two names for the same property?
For the tables, you could rename them and then create a synonym with the old name pointing to the new name.
For the columns, changing their name will break your application.You could create computed columns with the old name as well, that simply display the value of the new named column though (but this seems a little silly).
Note, however, that a computed column cannot reference another computed column, so you would have to duplicate the column in its entirety. That could lead to problems down the line if you don't update the definition of both columns.
A view containing a simple select statement acts exactly like a table. You really need to fix this properly across the database and applications. However if you want to go the view route, I suggest you do this:
Say you have a table called MyTable that you rename TheTable and with a column called MyColumn that you want to rename to TheColumn
Create a schema, say, new
Move the original table into it with this ALTER SCHEMA new TRANSFER MyTable
Rename the table and column.
Now you have a table called new.TheTable with a column called TheColumn. Everything is broken
Lastly, create a view that looks just like the old table
CREATE VIEW dbo.MyTable
AS
SELECT Column1, Column2, Column3, TheColumn As MyColumn
FROM new.TheTable;
Now everything works again.
All your fixed 'new' tables are in the new schema
However now everything is extra complicated
This is basically an illustration that you should just fix it properly across the whole app one at a time with careful change management. Definitely don't complicate it with triggers
Since you are using code first with multiple web and desktop applications, you are likely managing database changes from one place through migrations and ignoring changes other places.
You can create an empty migration and add code that will change the table name and column names to what you want. The migration should then create a view that will select from that table with the original table and column names. When you apply this migration, everything should still be working as normal from all applications. There are no model changes since you didn’t touch the model classes. Inserts, updates, and deletes will still happen through the view. There is no need for potentially buggy triggers or synonyms on the table in this option.
Now that you have the table changed, you can focus on the application code. If it helps, you can add annotations over the column and table names and start refactoring the code. You need to make sure you don’t make model changes that will break the other apps. If apps ignore model changes, you can get away with adding annotations over the columns and classes on all the apps before refactoring. You can get rid of the view sooner this way.
From this post....
http://blogs.msdn.com/b/ssdt/archive/2012/06/26/composite-projects-and-schema-compare.aspx
...it seems that (Same) Database References are a way to share common parts of a database.
If a specific database needs additional columns on a table from a (Same) Database Reference is there any way of handling that?
I was hoping you might be able to override the definition of a table from a Database Reference simply by re-declaring the table in the referencing Database Project.
e.g. if you had a Employee table in a Common Database project, a definition for Employee table in a Client Database referencing Common Database would override the definition in the Common project. Instead when you go to deploy the porject you get the error...
SQL71508: The model already has an element that has the same name dbo.Employee.
EDIT:
Anticipating the feedback below, the resolution I've made is to not use database references for the existing client databases. Instead I've created a structure as follows....
+OurCompanyDatabases
+Common
Common.sqlproj
+dbo...
+ClientA
+dbo....
+ClientB
+dbo....
ClientA.sqlproj
ClientB.sqlproj
So I've got multiple sqlproj files within the same folder and I include and exclude files from the projects as required.
So for example ClientA's Sales table has a ClientARewardsID column added I exclude the Sales table within the /OurCompanyDatabases/Common/dbo folder and create add a new Sales table within the /OurCompanyDatabases/ClientA/dbo folder.
This way Client A and Client B can retain the full use of SSDT update and deployment, whilst minimizing the duplication of sql scripts. I'm hoping this will reduce the cost of maintenance on the sites.
Going forward I will use database references and additional columns will be added in new tables with a foreign 1:1 foreign key relationship with the Common table.
No it doesn't support an inheritance type model and you can only really share complete objects so in your case you would have it structured like:
proj a - TableA
references - proj shared
proj b - TableA
references - proj shared
proj shared - TableXYZ
Then you can have two different definitions of TableA but still share all of the objects that are the same.
There is another option you could not include the table definition in SSDT or include one or the other and then handle any changes and the deployment yourself in post deploy scripts and use my filter (http://agilesqlclub.codeplex.com/) to stop ssdt deploying any changes to your table but this sort of invalidates one of the main reasons for using ssdt (merge type deployments for free).
ed
It's much safer and better practise to add a new table for the extra columns, and make its primary key a foreign key to the table it extends.
I am implementing a database for a translation dictionary, and am using the design indicated here.
Is there any way to update an entry in the translation table? Or would you need to have a primary key as well in order to facilitate any updates? Ideally, there wouldn't need to be updates, but it is conceivable a translation could be incorrect and need to be changed.
It seems you could delete the incorrect translation and insert a new one. In my case, I have a server DB, and an Android app that will pull down the languages it needs, and the associated words and translations, into a local DB. In this case, while it may be simple to delete the incorrect translation on the server, how would the client know, unless it deleted and repopulated the entire translation table?
Is a primary key, then a UNIQUE constraint on the two word_id columns the best way around this?
You can update an entry in the translation table with a statement such as:
update TRANSLATION_EN_DE
set ID_DE = 3
where ID_DE = 2 and
ID_EN = 1;
I would not have one table per language though.
Add a new table for unique languages, and add its primary key to a words table that holds all languages.
Then your translation table would be "word_from" and "word_to".
It will make your design and code much more simple.
To propagate changes to the client you'd probably want to version all of the changes in a new column on all tables to take account of new words/translations, spelling corrections, possible removal of words/translations, and have the client record the version number up to which it has retrieved data.
Since you might have deletes that you want to propagate you'll need to use a "soft delete" flag in the tables, because otherwise there would be no record in the table to hold the version number.
You'd probably also want a table holding those version numbers as a unique key with a text to explain the type of changes that have taken place, and the timestamp for the change. Remove the timestamp columns from all other tables.
So when you make a new batch of changes, create a new version record, make all of the required changes, and then commit all changes in a single transaction. then the entire change set becomes visible to other database users, and they can very efficiently check whether they are up to date or not, and retrieve only the relevant changes.
I am very new to MS Access and I am struggling with some things that seem like they should be the most basic. I have imported a table of data from Excel and have defined the data types for the fields. I have no problem there, but now I want to make a new table that has as a primary key one of the fields from the imported table. It looks like I can manually create this table, set the relationship, and then go back and type in each record associated with the new primary key, but this seems completely ridiculous. Surely there must be a way to automatically create one record for each unique instance in the matching field from the original table. Yet, I've scrolled through hundreds of pages of Access tutorials and Googled the question and found no satisfactory guidance.
Do I completely misunderstand what Access is all about? How do I create a new table with entries from a field on an existing table? What am I missing?
You don't specify which version of Access you are using, the suggestions listed below apply to 2010, but should be similar is other versions.
You can create new tables from existing tables using either a 'Make Table' option after selecting 'Create' -> 'Query Design', or you can manually create your table first, then use an 'Append' query.
Without knowing the design of your table it's hard to get more descriptive.
Are you populating your new table's primary key ahead of time, or relying on Auto Number to do it (preferred method)?
Why does SQL 2008 all of a sudden want to drop my tables when I go to change the column type from say int to real? This never happened in SQL 2005 to my knowledge. Any insight would be helpful please.
I can't believe the top answer has been sitting here for so long - it is very dangerous advice!
There are few operations that you can do inplace without dropping your table:
Expand a varchar column https://dba.stackexchange.com/questions/5211/changing-column-width
Make a column nullable (but not vice-versa)
Renaming columns using sp_rename
If you find yourself in the situation where altering a column is not possible without dropping the table, you can usually use a SELECT INTO query to project your data into a new table, then drop the old table (temporarily disabling constraints) and then renaming the projected table. You will need to take your database offline for maintenance in this case though.
In SQL Server 2008, go to Tools >> Options. In the little window, click "Designer". Uncheck "Prevent saving changes that require ..."
=====
Edited on Sept 4th, 2015.
I have added this answer here a long, long time ago describing the way I would solve the situation described on the question above. Since then, users on the threads below have exposed several concerns on doing things the way I recommended at the time. Basically, the solution I described could be problematic on some scenarios. I then suggest you to keep on reading to check other users' comments and pick the best solution for you.
Here is what I use:
-- Add new column
ALTER TABLE MyTable
ADD Description2 VARCHAR(MAX)
GO
-- Copy data to new column (probably with modifications)
Update MyTable
SET Description2 = Description
GO
-- Drop old column
ALTER TABLE MyTable
DROP COLUMN Description
GO
-- Rename new column to the original column's name.
sp_RENAME 'MyTable.Description2' , 'Description', 'COLUMN'
GO
Copy the data into a new column.
Drop the old column.
Rename the new column to the old column's name.
I have the same issue. Athough my account has sa rights if I try using another sa account it works. It seems that somehow my account does not have the ability to alter. still investigating, but it is a permission issue.
update:
I cannot expain it. but this is what I did. there two domain groups my account belonged to. One was a new AD domain group and the other was an NT legay domain group. Once I removed the legacy domain group I was able to alter the table successfully. Mind you both groups had "sa" priviliges.
The behavior was that the alter commands would result in success, but nothing changed on the table. Then when I manually tried to change the fields through the designer it complained that I was not allowed to make change if it required to drop and recreate the table. I found the setting in tools and I was able to turn that off. But this table is huge and not a good idea to do this. I woud advise others against it.
so it was a permission issue. I can't explain how, but I hope it helps someone else
Another way to this without totally dropping the table is
Take a backup of the column values.
Make the column nullable if it does not already allow nulls. Set the column values to be null by
doing
update tablename set columnname = null
Delete the column
Insert a new column with the same name as the deleted column and the type which you want
Insert the saved data into this column