367

I'm adding a new, "NOT NULL" column to my Postgresql database using the following query (sanitized for the Internet):

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL;

Each time I run this query, I receive the following error message:

ERROR:  column "mycolumn" contains null values

I'm stumped. Where am I going wrong?

NOTE: I'm using pgAdmin III (1.8.4) primarily, but I received the same error when I ran the SQL from within Terminal.

8 Answers 8

563

You have to set a default value.

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL DEFAULT 'foo';

... some work (set real values as you want)...

ALTER TABLE mytable ALTER COLUMN mycolumn DROP DEFAULT;
Sign up to request clarification or add additional context in comments.

4 Comments

@SeanBright , you can access to postgres doc offline by doing man ALTER_TABLE :)
To clarify: the default value is only needed to update existing rows, which is why it can be dropped immediately afterwards. All existing rows have been updated when the table was altered (which may take some time, obviously)
This won't work if you want to use another column to compute the initial value for existing rows. j_random_hacker's answer allows for that, making it more robust.
It works but the accepted answer IMO should be @j_random_hacker. Firstly for the reason described above, secondly it's imo abusing default values since the goal never is to set a default value and we don't really need to. The goal is to set values and have it not nullable in which case the other answer is strictly better. PS, I've seen devs use this advice and forget the DROP Default, I'd prefer they forget the NOT NULL in that case instead of suddenly having an ID 1 with thousands of relations towards later on when bugs arise :)
136

As others have observed, you must either create a nullable column or provide a DEFAULT value. If that isn't flexible enough (e.g. if you need the new value to be computed for each row individually somehow), you can use the fact that in PostgreSQL, all DDL commands can be executed inside a transaction:

BEGIN;
ALTER TABLE mytable ADD COLUMN mycolumn character varying(50);
UPDATE mytable SET mycolumn = timeofday();    -- Just a silly example
ALTER TABLE mytable ALTER COLUMN mycolumn SET NOT NULL;
COMMIT;

1 Comment

even in a transaction, NOT NULL is enforced immediately, so must first add column, fill values, then add NOT NULL — as this answer does. (tested on postgres 9.6)
56

Since rows already exist in the table, the ALTER statement is trying to insert NULL into the newly created column for all of the existing rows. You would have to add the column as allowing NULL, then fill the column with the values you want, and then set it to NOT NULL afterwards.

1 Comment

Example of how to do it would have been really nice. Otherwise, Luc's solution seems to be more complete and ready to use.
8

this query will auto-update the nulls

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) DEFAULT 'whatever' NOT NULL;

1 Comment

True, but it also keeps the default around, so any new values added to the table will have NULL for mycolumn if not otherwise specified. The question states that it wants the column to be NOT NULL, so this doesn't fully achieve the stated goal.
6

You either need to define a default, or do what Sean says and add it without the null constraint until you've filled it in on the existing rows.

Comments

3

Specifying a default value would also work, assuming a default value is appropriate.

1 Comment

It would improve the answer to give the amended syntax to create the column with a default value (for illustration).
-1

Or, create a new table as temp with the extra column, copy the data to this new table while manipulating it as necessary to fill the non-nullable new column, and then swap the table via a two-step name change.

Yes, it is more complicated, but you may need to do it this way if you don't want a big UPDATE on a live table.

5 Comments

I didn't -1 you, but I think there may be subtle difficulties with this -- e.g. I'm betting that existing indices, triggers and views will continue to refer to the original table even after the rename as I think they store the relid of the table (which doesn't change) rather than its name.
Yes, I should have stated that the new table should be an exact copy of the original, including adding indices and such. My bad for being too brief. The reason for this is that there are also subtle diffculties of performing an ALTER on a table that may be live, and sometimes you need to stage it.
For example, using the DEFAULT approach, you'll add that default value to each row. Not sure how Postgres locks up a table when doing this. Or, if column order matters, you can't just add a column with the ALTER command.
Fair enough, ALTER TABLE does lock the table according to the PostgreSQL docs, however your non-transactional approach risks losing changes if the table is indeed live. Also I'd suggest that any code that relies on column order is broken (that may be outside your control of course).
This approach is also particularly problematic if the table is referenced by foreign key indexes as those would all have to be recreated as well.
-23

This worked for me: :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;

1 Comment

There is no NOT NULL constraint on your query. Of course it's working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.