How to add column if not exists on PostgreSQL?

PostgresqlPostgresql 9.1

Postgresql Problem Overview


Question is simple. How to add column x to table y, but only when x column doesn't exist ? I found only solution here how to check if column exists.

SELECT column_name 
FROM information_schema.columns 
WHERE table_name='x' and column_name='y';

Postgresql Solutions


Solution 1 - Postgresql

With Postgres 9.6 this can be done using the option if not exists

ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;

Solution 2 - Postgresql

Here's a short-and-sweet version using the "DO" statement:

DO $$ 
    BEGIN
        BEGIN
            ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
        EXCEPTION
            WHEN duplicate_column THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
        END;
    END;
$$

You can't pass these as parameters, you'll need to do variable substitution in the string on the client side, but this is a self contained query that only emits a message if the column already exists, adds if it doesn't and will continue to fail on other errors (like an invalid data type).

I don't recommend doing ANY of these methods if these are random strings coming from external sources. No matter what method you use (client-side or server-side dynamic strings executed as queries), it would be a recipe for disaster as it opens you to SQL injection attacks.

Solution 3 - Postgresql

Postgres 9.6 added ALTER TABLE tbl ADD COLUMN IF NOT EXISTS column_name.
So this is mostly outdated now. You might use it in older versions, or a variation to check for more than just the column name.


CREATE OR REPLACE function f_add_col(_tbl regclass, _col  text, _type regtype)
  RETURNS bool
  LANGUAGE plpgsql AS
$func$
BEGIN
   IF EXISTS (SELECT FROM pg_attribute
              WHERE  attrelid = _tbl
              AND    attname  = _col
              AND    NOT attisdropped) THEN
      RETURN false;
   ELSE
      EXECUTE format('ALTER TABLE %s ADD COLUMN %I %s', _tbl, _col, _type);
      RETURN true;
   END IF;
END
$func$;

Call:

SELECT f_add_col('public.kat', 'pfad1', 'int');

Returns true on success, else false (column already exists).
Raises an exception for invalid table or type name.

Why another version?

> Tip > > A block containing an EXCEPTION clause is significantly more > expensive to enter and exit than a block without one. > Therefore, don't use EXCEPTION without need.

Solution 4 - Postgresql

Following select query will return true/false, using EXISTS() function.

> EXISTS():
The argument of EXISTS is an arbitrary SELECT statement, or > subquery. The subquery is evaluated to determine whether it returns > any rows. If it returns at least one row, the result of EXISTS is > "true"; if the subquery returns no rows, the result of EXISTS is > "false"

SELECT EXISTS(SELECT  column_name 
                FROM  information_schema.columns 
               WHERE  table_schema = 'public' 
                 AND  table_name = 'x' 
                 AND  column_name = 'y'); 

and use the following dynamic SQL statement to alter your table

DO
$$
BEGIN
IF NOT EXISTS (SELECT column_name 
                 FROM  information_schema.columns 
                WHERE  table_schema = 'public' 
                  AND  table_name = 'x' 
                  AND  column_name = 'y') THEN
ALTER TABLE x ADD COLUMN y int DEFAULT NULL;
ELSE
RAISE NOTICE 'Already exists';
END IF;
END
$$

Solution 5 - Postgresql

For those who use Postgre 9.5+(I believe most of you do), there is a quite simple and clean solution

ALTER TABLE if exists <tablename> add if not exists <columnname> <columntype>

Solution 6 - Postgresql

the below function will check the column if exist return appropriate message else it will add the column to the table.

create or replace function addcol(schemaname varchar, tablename varchar, colname varchar, coltype varchar)
returns varchar 
language 'plpgsql'
as 
$$
declare 
    col_name varchar ;
begin 
      execute 'select column_name from information_schema.columns  where  table_schema = ' ||
      quote_literal(schemaname)||' and table_name='|| quote_literal(tablename) || '   and    column_name= '|| quote_literal(colname)    
      into   col_name ;   

      raise info  ' the val : % ', col_name;
      if(col_name is null ) then 
          col_name := colname;
          execute 'alter table ' ||schemaname|| '.'|| tablename || ' add column '|| colname || '  ' || coltype; 
      else
           col_name := colname ||' Already exist';
      end if;
return col_name;
end;
$$

Solution 7 - Postgresql

This is basically the solution from sola, but just cleaned up a bit. It's different enough that I didn't just want to "improve" his solution (plus, I sort of think that's rude).

Main difference is that it uses the EXECUTE format. Which I think is a bit cleaner, but I believe means that you must be on PostgresSQL 9.1 or newer.

This has been tested on 9.1 and works. Note: It will raise an error if the schema/table_name/or data_type are invalid. That could "fixed", but might be the correct behavior in many cases.

CREATE OR REPLACE FUNCTION add_column(schema_name TEXT, table_name TEXT, 
column_name TEXT, data_type TEXT)
RETURNS BOOLEAN
AS
$BODY$
DECLARE
  _tmp text;
BEGIN

  EXECUTE format('SELECT COLUMN_NAME FROM information_schema.columns WHERE 
    table_schema=%L
    AND table_name=%L
    AND column_name=%L', schema_name, table_name, column_name)
  INTO _tmp;

  IF _tmp IS NOT NULL THEN
    RAISE NOTICE 'Column % already exists in %.%', column_name, schema_name, table_name;
    RETURN FALSE;
  END IF;

  EXECUTE format('ALTER TABLE %I.%I ADD COLUMN %I %s;', schema_name, table_name, column_name, data_type);

  RAISE NOTICE 'Column % added to %.%', column_name, schema_name, table_name;

  RETURN TRUE;
END;
$BODY$
LANGUAGE 'plpgsql';

usage:

select add_column('public', 'foo', 'bar', 'varchar(30)');

Solution 8 - Postgresql

Can be added to migration scripts invoke function and drop when done.

create or replace function patch_column() returns void as
$$
begin
    if exists (
        select * from information_schema.columns
            where table_name='my_table'
            and column_name='missing_col'
     )
    then
        raise notice 'missing_col already exists';
    else
        alter table my_table
            add column missing_col varchar;
    end if;
end;
$$ language plpgsql;

select patch_column();

drop function if exists patch_column();

Solution 9 - Postgresql

In my case, for how it was created reason it is a bit difficult for our migration scripts to cut across different schemas.

To work around this we used an exception that just caught and ignored the error. This also had the nice side effect of being a lot easier to look at.

However, be wary that the other solutions have their own advantages that probably outweigh this solution:

DO $$
BEGIN
  BEGIN
    ALTER TABLE IF EXISTS bobby_tables RENAME COLUMN "dckx" TO "xkcd";
  EXCEPTION
    WHEN undefined_column THEN RAISE NOTICE 'Column was already renamed';
  END;
END $$;

Solution 10 - Postgresql

You can do it by following way.

ALTER TABLE tableName drop column if exists columnName;	
ALTER TABLE tableName ADD COLUMN columnName character varying(8);

So it will drop the column if it is already exists. And then add the column to particular table.

Solution 11 - Postgresql

Simply check if the query returned a column_name.

If not, execute something like this:

ALTER TABLE x ADD COLUMN y int;

Where you put something useful for 'x' and 'y' and of course a suitable datatype where I used int.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmariooshView Question on Stackoverflow
Solution 1 - Postgresqla_horse_with_no_nameView Answer on Stackoverflow
Solution 2 - PostgresqlMatthew WoodView Answer on Stackoverflow
Solution 3 - PostgresqlErwin BrandstetterView Answer on Stackoverflow
Solution 4 - PostgresqlVivek S.View Answer on Stackoverflow
Solution 5 - PostgresqlLeonView Answer on Stackoverflow
Solution 6 - PostgresqlsolaimuruganvView Answer on Stackoverflow
Solution 7 - PostgresqlDavid SView Answer on Stackoverflow
Solution 8 - Postgresqluser645527View Answer on Stackoverflow
Solution 9 - PostgresqlThinkBonoboView Answer on Stackoverflow
Solution 10 - PostgresqlparthivrshahView Answer on Stackoverflow
Solution 11 - PostgresqlErwin MollerView Answer on Stackoverflow