315

In a MySQL script you can write:

CREATE TABLE IF NOT EXISTS foo ...;

... other stuff ...

and then you can run the script many times without re-creating the table.

How do you do this in PostgreSQL?

0

6 Answers 6

480

This feature has been implemented in Postgres 9.1:

CREATE TABLE IF NOT EXISTS myschema.mytable (i integer);


For older versions, here is a function to work around it:

CREATE OR REPLACE FUNCTION create_mytable()
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   IF EXISTS (SELECT FROM pg_catalog.pg_tables 
              WHERE  schemaname = 'myschema'
              AND    tablename  = 'mytable') THEN
      RAISE NOTICE 'Table myschema.mytable already exists.';
   ELSE
      CREATE TABLE myschema.mytable (i integer);
   END IF;
END
$func$;

Call:

SELECT create_mytable();        -- call as many times as you want. 

Notes

The columns schemaname and tablename in pg_tables are case-sensitive. If you double-quote identifiers in the CREATE TABLE statement, you need to use the exact same spelling. If you don't, you need to use lower-case strings. See:

pg_tables only contains actual tables. The identifier may still be occupied by related objects. See:

If the role executing this function does not have the necessary privileges to create the table you might want to use SECURITY DEFINER for the function and make it owned by another role with the necessary privileges. This version is safe enough.

4
  • I'm being forced to use an existing postgres 8.4 database. This hack does the trick, thank you!
    – Boundless
    Commented May 29, 2012 at 20:24
  • 1
    @Boundless: I saw that your edit was rejected as "too minor". I applied it, because it won't hurt. However, you should execute the CREATE FUNCTION only once. It's SELECT create_mytable(); that you may want to call many times. Commented May 30, 2012 at 3:03
  • 1
    Brandstetter: I agree with you. The problem that I ran into was that I didn't know if the function was created or not (just like the table may or may not exist). So I want to make sure the function is created before I call it.
    – Boundless
    Commented May 30, 2012 at 13:57
  • 1
    btw, the opposite DROP TABLE IF EXISTS <tablename> is also supported.
    – Krumelur
    Commented Aug 11, 2021 at 17:31
181

Try this:

CREATE TABLE IF NOT EXISTS app_user (
  username varchar(45) NOT NULL,
  password varchar(450) NOT NULL,
  enabled integer NOT NULL DEFAULT '1',
  PRIMARY KEY (username)
)
6
  • this is actually the cleaner solution. should be upvoted.
    – SDReyes
    Commented Feb 26, 2016 at 16:42
  • 4
    in fact, I'm terrified of how many solutions involving 'function' there are.
    – SDReyes
    Commented Feb 26, 2016 at 16:43
  • 13
    @SDReyes those other solutions were posted prior to Postgres 9.1 which included the IF NOT EXISTS option.
    – Kris
    Commented Jun 10, 2016 at 3:58
  • 4
    Not sure how this answer contributed as @erwin-brandstetter answer was complete in itself.
    – comiventor
    Commented Jan 9, 2018 at 7:45
  • @comiventor correct, this one does how ever show that the parameter usage is.The leading answer i did not spot that until i saw this one. This does help a bit.
    – Angry 84
    Commented Mar 16, 2018 at 9:32
10

I created a generic solution out of the existing answers which can be reused for any table:

CREATE OR REPLACE FUNCTION create_if_not_exists (table_name text, create_stmt text)
RETURNS text AS
$_$
BEGIN

IF EXISTS (
    SELECT *
    FROM   pg_catalog.pg_tables 
    WHERE    tablename  = table_name
    ) THEN
   RETURN 'TABLE ' || '''' || table_name || '''' || ' ALREADY EXISTS';
ELSE
   EXECUTE create_stmt;
   RETURN 'CREATED';
END IF;

END;
$_$ LANGUAGE plpgsql;

Usage:

select create_if_not_exists('my_table', 'CREATE TABLE my_table (id integer NOT NULL);');

It could be simplified further to take just one parameter if one would extract the table name out of the query parameter. Also I left out the schemas.

4

This solution is somewhat similar to the answer by Erwin Brandstetter, but uses only the sql language.

Not all PostgreSQL installations has the plpqsql language by default, this means you may have to call CREATE LANGUAGE plpgsql before creating the function, and afterwards have to remove the language again, to leave the database in the same state as it was before (but only if the database did not have the plpgsql language to begin with). See how the complexity grows?

Adding the plpgsql may not be issue if you are running your script locally, however, if the script is used to set up schema at a customer it may not be desirable to leave changes like this in the customers database.

This solution is inspired by a post by Andreas Scherbaum.

-- Function which creates table
CREATE OR REPLACE FUNCTION create_table () RETURNS TEXT AS $$
    CREATE TABLE table_name (
       i int
    );
    SELECT 'extended_recycle_bin created'::TEXT;
    $$
LANGUAGE 'sql';

-- Test if table exists, and if not create it
SELECT CASE WHEN (SELECT true::BOOLEAN
    FROM   pg_catalog.pg_tables 
    WHERE  schemaname = 'public'
    AND    tablename  = 'table_name'
  ) THEN (SELECT 'success'::TEXT)
  ELSE (SELECT create_table())
END;

-- Drop function
DROP FUNCTION create_table();
1
  • Your solution is great even when plpgsql is available. It's easy extendable for creation of views and functions on objects not existing at point of time. E.g. views on tables from foreign servers. You saved my day! Thanks!
    – Alex Yu
    Commented Apr 26, 2020 at 16:22
4

There is no CREATE TABLE IF NOT EXISTS... but you can write a simple procedure for that, something like:

CREATE OR REPLACE FUNCTION execute(TEXT) RETURNS VOID AS $$
BEGIN
  EXECUTE $1;
END; $$ LANGUAGE plpgsql;


SELECT 
  execute($$
      CREATE TABLE sch.foo 
      (
        i integer
      )
  $$) 
WHERE 
  NOT exists 
  (
    SELECT * 
    FROM information_schema.tables 
    WHERE table_name = 'foo'
      AND table_schema = 'sch'
  );
1
3

There is no CREATE TABLE IF NOT EXISTS... but you can write a simple procedure for that, something like:

CREATE OR REPLACE FUNCTION prc_create_sch_foo_table() RETURNS VOID AS $$
BEGIN

EXECUTE 'CREATE TABLE /* IF NOT EXISTS add for PostgreSQL 9.1+ */ sch.foo (
                    id serial NOT NULL, 
                    demo_column varchar NOT NULL, 
                    demo_column2 varchar NOT NULL,
                    CONSTRAINT pk_sch_foo PRIMARY KEY (id));
                   CREATE INDEX /* IF NOT EXISTS add for PostgreSQL 9.5+ */ idx_sch_foo_demo_column ON sch.foo(demo_column);
                   CREATE INDEX /* IF NOT EXISTS add for PostgreSQL 9.5+ */ idx_sch_foo_demo_column2 ON sch.foo(demo_column2);'
               WHERE NOT EXISTS(SELECT * FROM information_schema.tables 
                        WHERE table_schema = 'sch' 
                            AND table_name = 'foo');

         EXCEPTION WHEN null_value_not_allowed THEN
           WHEN duplicate_table THEN
           WHEN others THEN RAISE EXCEPTION '% %', SQLSTATE, SQLERRM;

END; $$ LANGUAGE plpgsql;

Not the answer you're looking for? Browse other questions tagged or ask your own question.