Question

A new column has been added to a table, but the new column was not added to the end of the table definition (rightmost column), but the middle of the table.

Table differences

When I try to commit this in Redgate SQL Source Control, I get the warning "These changes may result in data loss"

  • Will data loss really occurr?
  • Is there a way preview the change script to confirm that no data will be lost?
    • Can I copy the script and easily turn it into a Migrations V2 script?
  • Will I just have to
    • Edit the table in SSMS and move the new column to the end
    • or write a migration script?
  • If so, are there any handy tools to do the repetitive stuff?
Was it helpful?

Solution

Up front disclosure that I work for Red Gate on SQL Source Control.

That change will need to re-create a table. By default SSMS won't let you save that change. However that option must have been disabled in SSMS. It's under Tools->Options->Designers->Table and Database Designers->Prevent saving changes that require a table re-creating.

Given that feature is disabled SQL Source Control has then picked that up as a potential data loss situation, and prompted to see if you want to add a migration script.

If other developers within your team pull this change in through a get latest, then SQL Source Control will let them about any potential data loss with more details, depending on the current state of their local database. If the only change is adding columns to an existing table then this will not drop the data in columns that are unchanged.

If you are deploying to another DB (e.g. staging/UAT/prod) and you have SQL Compare you can use that to see exactly what will be applied to a DB if you try and run this against another non-local database. Choose the create deployment script option and you can sanity check the SQL before running.

As you say adding the column to the end of the table will avoid the need for the rebuild, so is probably the simplest way to avoid this if you don't need to worry about where the column is.

Alternatively you can add a migration script to:

  1. Create a new table with the new structure using a temp name
  2. Copy the existing data to the temp table
  3. Drop the existing table
  4. Rename the new temp table to the original name

You mention Migrations v2, the beta feature that changes how migrations work in order to better support branching and merging and DVCS systems. See http://www.red-gate.com/migrations

Version 1 migration scripts will need some modifications in order to be converted to a v2 migration script. It's a fairly trivial change. We're working on documenting this at the moment, and please reach out to us on the Google Group if you'd like more information on this change. https://groups.google.com/forum/#!forum/red-gate-migrations

OTHER TIPS

I moved the column to the end of the table using SSMS to negate the need for a migration script.

In a similar scenario, where it was not convenient to move the column, this is what I did to convert an SSMS script to a Migrations V2 script.

  • Undo the change in SSMS (deleted the column)
  • Redo the change in SSMS, but instead of saving the change direct to the database, I saved the change script
  • Modified the change script
    • Trimmed the SSMS transaction & environment wrapper
    • Added a guard clause: IF COL_LENGTH('MyTable','MyColumn') IS NULL
    • Wrapped the script in BEGIN TRAN - ROLLBACK TRAN to test the script without dirtying the database
    • Replaced GO with END BEGIN
    • Tested within rolled-back transaction
    • Removed BEGIN TRAN - ROLLBACK TRAN development wrapper

Visual diff of converting SSMS to Redgate

Here is the simple sql query that will help to insert column in database table without data loss.

Lets say CCDetails is the table in which we want to insert column GlobaleNote just before column Sys_CreatedBy:

declare @str1 nvarchar(1000)
declare @tableName nvarchar(1000)
set @tableName='CCDetails'
set @str1 = ''
SELECT @str1 = @str1 + ', ' + COLUMN_NAME
FROM Information_Schema.Columns
WHERE Table_Name = @tableName 
ORDER BY Ordinal_Position
set @str1 = right(@str1, len(@str1) - 2)
set @str1 = 'select ' + @str1 +'  into '+@tableName+'Temp from '+@tableName+' ; Drop Table '+ @tableName + ' ; EXEC sp_rename '+@tableName+'Temp, '+@tableName
set @str1 = REPLACE(@str1,'Sys_CreatedBy','CAST('''' as nvarchar(max)) As GlobaleNote , Sys_CreatedBy' )

exec sp_executesql @str1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top