As an option you can initially create Null-able column, then update your table column with valid not null values and finally ALTER column to set NOT NULL constraint:

ALTER TABLE MY_TABLE ADD STAGE INT NULL
GO
UPDATE MY_TABLE SET <a valid not null values for your column>
GO
ALTER TABLE MY_TABLE ALTER COLUMN STAGE INT NOT NULL
GO

Another option is to specify correct default value for your column:

ALTER TABLE MY_TABLE ADD STAGE INT NOT NULL DEFAULT '0'

UPD: Please note that answer above contains GO which is a must when you run this code on Microsoft SQL server. If you want to perform the same operation on Oracle or MySQL you need to use semicolon ; like that:

ALTER TABLE MY_TABLE ADD STAGE INT NULL;
UPDATE MY_TABLE SET <a valid not null values for your column>;
ALTER TABLE MY_TABLE ALTER COLUMN STAGE INT NOT NULL;
Answer from Pavel Morshenyuk on Stack Overflow
🌐
W3Schools
w3schools.com › sql › sql_notnull.asp
SQL NOT NULL Constraint
The following SQL creates a "Persons" ... ); To define a NOT NULL constraint on an existing table, use ALTER TABLE and add NOT NULL after the data type of the column name....
🌐
Qlik Community
community.qlik.com › t5 › Suggest-an-Idea › MS-SQL-Server-Adding-a-NOT-NULL-column-to-an-existing-table › idi-p › 1968370
MS SQL Server: Adding a NOT NULL column to an existing table
December 20, 2022 - It appears to execute a statement like this: ALTER <table> ADD <column> <data_type> NULL The key impact of this is when the source table has data in it prior to this change. In that case it results in material differences between source and target: ...
🌐
PopSQL
popsql.com › learn-sql › sql-server › how-to-add-a-not-null-constraint-in-sql-server
SQL Server Not Null: How to Add using Alter Table - PopSQL
Learn how to add a NOT NULL constraint in SQL Server for a specific column. Use the "ALTER TABLE" command with "ALTER COLUMN" and specify the "NOT NULL" attribute in the column definition to enforce data validation.
🌐
TutorialsPoint
tutorialspoint.com › how-to-add-a-not-null-column-in-mysql
How to add a NOT NULL column in MySQL?
mysql> create table AddNotNull -> ( -> Id int, -> Name varchar(100) -> ); Query OK, 0 rows affected (1.43 sec) Here is the query to add a not null column in an existing table using alter command.
🌐
Redgate Software
red-gate.com › home › learning & community › product learning › problems with adding not null columns or making nullable columns not null (ei028)
Problems with adding NOT NULL columns or making nullable columns NOT NULL (EI028) | Redgate
August 6, 2019 - Msg 515, Level 16, State 2, Line 58 Cannot insert the value NULL into column 'Word', table 'PhilFactor.dbo.CountingWords'; column does not allow nulls. UPDATE fails. The statement has been terminated. Listing 4: Failed attempt to make the Word column NOT NULL · Aiee! We still can’t make column non-nullable, even though we’ve told SQL Server what to insert for NULL columns! First, we must remove any existing NULLs explicitly, by updating all the rows with the default value:
🌐
Viget
viget.com › articles › adding-a-not-null-column-to-an-existing-table
Adding a NOT NULL Column to an Existing Table | Viget
March 9, 2016 - StandardError: An error has occurred, this and all later migrations canceled: SQLite3::SQLException: Cannot add a NOT NULL column with default value NULL: ALTER TABLE "employees" ADD "age" integer NOT NULL
Top answer
1 of 1
23

I'll share how I have done this in the past. It is designed to solve the specific limitation of pre-deployment scripts that you call out in your second point:

Adding the column in a pre-deployment script will fail the publish when it automatically tries to create the same column, a second time (even if the pre-deployment script is written to be idempotent)

Why pre-deployment scripts don't work for this

When you deploy an SSDT project, the way it stitches thing together is like this (a bit simplified, but in general):

  1. Do the "schema compare" between the source (dacpac file) and the target (database)
  2. Generate a deployment script based on the results of that compare
  3. Process any pre-deployment scripts in the dacpac (doing token replacement, etc.) and insert the contents into the beginning of the deployment script
  4. Do the same for post-deployment scripts, appending to the end of the deployment script

When a new column exists in the dacpac and not in the target database, step #2 will generate code to add that column. So if the pre-deployment script adds this column, the main part of the script will fail (because it assumes the column doesn't exist, based on the results of the schema compare in step #1)

Solution: pre-SSDT script

Martin Smith mentioned this option in a comment, and it's the solution that has worked best for me so far:

We use premodel scripts in our deplyment pipeline. This is not something that is part of SSDT but a step that runs before the dacfx publish. So in this case the premodel script could add the column with the desired values and make it not null and by the time the publish happens it is already in the state expected by SSDT so it doesnt have anything to do. I'm still yet to find much use for predeploy scripts. – Martin Smith

The steps to implement this solution in general are:

  1. Create a script in the SSDT project to hold your "pre-SSDT" T-SQL code
    • Depending on how your deployment process works, code in these files should probably be idempotent
  2. Make sure to set this script to "Build Action=None" and "Copy to Output Directory=Copy always" - the "copy always" option is especially important, as the deployment process needs to be able to find this script in your deployment artifacts
  3. In your deployment process, locate and run this script (or scripts) before the SSDT schema compare occurs
  4. Once that script has been executed successfully, you can engage DacServices / DacFx / whatever to complete your deployment as usual

In the end, this allows you to add the column using whatever custom code you like, populated using complex business logic, in the pre-SSDT script.

You also add the column definition in the SSDT project (so source control still matches the real life state of the database). But when the schema compare runs, it sees no changes related to that column (because you've already deployed it).

Other uses of pre-SSDT

I often find when testing deployments that SSDT performs a "table rebuild" operation* when it's completely unnecessary. This is where a new table is a created with the updated schema, all data is copied to that table, the old table is dropped, and the new table is renamed to replace the old table.

This can lead to massive transaction log file growth and other problems if the table is large. If I notice that a schema change is causing this, I'll instead make the change myself in pre-SSDT (which is usually a simple ALTER TABLE statement) and avoid the table rebuild.

Is this a good idea?

I think so. If you read Critiquing two different approaches to delivering databases: Migrations vs state by Alex Yates, this is essentially combining the two approaches a bit. SSDT is state based, but we incorporate a migration step (before SSDT) to handle some of the more complex scenarios that SSDT just has no way of dealing with in a general way.

In doing some searching while writing this answer, this is actually a very common approach discussed in the SSDT user community once you know what to search for. I've seen it called:

  • pre-compare
  • pre-model
  • pre-DAC
  • pre-SSDT

Etc. Here's a great article that covers a lot of the points that I mentioned above:

Pre-Compare & Pre-Deployment Scripts to SSDT

And one from Red Gate (in the #4 – Changing from system type to user defined type section) that also refers to this as pre-compare:

How to Fix Ten SSDT Deployment Snags, With or Without ReadyRoll

So what's the point of pre-deployment scripts?

Martin points out that he hasn't found "much use for predeploy scripts." I tend to feel the same way. But there are scenarios where they can be useful.

One example a coworker pointed out to me was storing some data in a temp table to be used in the post deployment script (say you're moving a column from one table to another).


*The table rebuild looks like this, which is horrifying, right?

GO
PRINT N'Starting rebuilding table [dbo].[MyTable]...';


GO
BEGIN TRANSACTION;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

CREATE TABLE [dbo].[tmp_ms_xx_MyTable] (
    [Id] BIGINT IDENTITY (1, 1) NOT NULL,
    -- etc, other columns
);

IF EXISTS (SELECT TOP 1 1 
           FROM   [dbo].[MyTable])
    BEGIN
        SET IDENTITY_INSERT [dbo].[tmp_ms_xx_MyTable] ON;
        INSERT INTO [dbo].[tmp_ms_xx_MyTable] ([Id], ...)
        SELECT   [Id],
                 -- etc, other columns
        FROM     [dbo].[MyTable]
        ORDER BY [Id] ASC;
        SET IDENTITY_INSERT [dbo].[tmp_ms_xx_MyTable] OFF;
    END

DROP TABLE [dbo].[MyTable];

EXECUTE sp_rename N'[dbo].[tmp_ms_xx_MyTable]', N'MyTable';

COMMIT TRANSACTION;

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Find elsewhere
🌐
Quora
quora.com › Can-I-add-NOT-NULL-constraint-after-table-creation
Can I add NOT NULL constraint after table creation? - Quora
Answer (1 of 7): Yes you can alter column definition by adding not null after table creation SQL SERVER : ALTER TABLE tablename ALTER COLUMN columnname datatype NOT NULL NOTE : Column must not contain any null value for above query to execute ...
🌐
Atlassian
atlassian.com › data › databases › how-to-alter-a-column-from-null-to-not-null-in-sql-server
How to alter a column from NULL to NOT NULL in SQL server
Changing the data structure of a column in SQL Server from NULL to NOT NULL, thereby disallowing non-null values in that column, is generally performed using the relatively simple ALTER TABLE syntax to appropriately change the column in question. In this tutorial we’ll examine the important safety precautions necessary when altering existing data in a column, prior to actually issuing any ALTER commands that would potentially cause harm to the table itself.
🌐
CastorDoc
castordoc.com › how-to › how-to-add-a-not-null-constraint-in-mysql
How to Add a NOT NULL Constraint in MySQL?
January 24, 2024 - The ALTER TABLE statement allows you to modify the structure of an existing table by adding, modifying, or removing columns and constraints. The ALTER TABLE command is used to add the NOT NULL constraint to a specific column in an existing table.
🌐
Tutorialspoint
tutorialspoint.com › sql › sql-not-null-constraint.htm
SQL - NOT NULL Constraint
You can add or remove the NOT NULL constraint on an existing table using the ALTER TABLE statement. Adding this constraint ensures that a column cannot store NULL values, while removing it allows NULL values in that column.
🌐
PostgreSQL
postgresql.org › docs › 7.3 › ddl-alter.html
PostgreSQL: Documentation: 7.3: Modifying Tables
January 1, 2012 - To add a not-null constraint, which cannot be written as a table constraint, use this syntax: ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
Top answer
1 of 2
6

Referencing the documentation for ALTER TABLE (highlighting mine),

The changes specified in ALTER TABLE are implemented immediately. If the changes require modifications of the rows in the table, ALTER TABLE updates the rows. ALTER TABLE acquires a schema modify (SCH-M) lock on the table to make sure that no other connections reference even the metadata for the table during the change, except online index operations that require a very short SCH-M lock at the end. In an ALTER TABLE…SWITCH operation, the lock is acquired on both the source and target tables. The modifications made to the table are logged and fully recoverable. Changes that affect all the rows in very large tables, such as dropping a column or, on some editions of SQL Server, adding a NOT NULL column with a default value, can take a long time to complete and generate many log records. These ALTER TABLE statements should be executed with the same care as any INSERT, UPDATE, or DELETE statement that affects many rows.

Also, Paul Randal has some good information about what happens when you add columns (and how long the operation might take) in Misconceptions around adding columns to a table. To summarize some main points:

  • New column is nullable, with a NULL default. The table’s metadata records the fact that the new column exists but may not be in the record. This is why the null bitmap also has a count of the number of columns in that particular record. SQL Server can work out whether a column is present in the record or not. So – this is NOT a size-of-data operation – the existing table records are not updated when the new column is added. The records will be updated only when they are updated for some other operation.
  • New column is nullable, with a non-NULL default. It depends which version of SQL Server you’re using:

    • Before SQL Server 2012: This IS a size-of-data operation. The non-NULL default forces all existing records to be updated when the column is added, and so the null bitmap will be updated too.

    • SQL Server 2012 onward: same behavior as for a NULL default nullable column (i.e. metadata only operation)

  • New column is not-nullable (obviously with a non-NULL default). This IS a size-of-data operation.
2 of 2
-2

the entire column will be null for all the records in the table


begin tran

ALTER TABLE MyTable ADD MyColumn varchar(255) NULL;

select MyColumn,* from MyTable

rollback


run this command and check what happens!!!

the code inside rollback update temporily so u can check ,, by modifying thecode also