PostgreSQL: Create table if not exists AS
CREATE TABLE IF NOT EXISTS ...
was added in Postgres 9.1. See:
- PostgreSQL create table if not exists
Postgres 9.0 or older
If you are going to write a function for this, base it on system catalog table pg_class
, not on views in the information schema or the statistics collector (which only exist if activated).
- How to check if a table exists in a given schema
CREATE OR REPLACE FUNCTION create_table_qry(_tbl text
, _qry text
, _schema text = NULL)
RETURNS bool
LANGUAGE plpgsql AS
$func$
DECLARE
_sch text := COALESCE(_schema, current_schema());
BEGIN
IF EXISTS (
SELECT FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = _sch
AND c.relname = _tbl
) THEN
RAISE NOTICE 'Name is not free: %.%',_sch, _tbl;
RETURN FALSE;
ELSE
EXECUTE format('CREATE TABLE %I.%I AS %s', _sch, _tbl, _qry);
RAISE NOTICE 'Table created successfully: %.%',_sch, _tbl;
RETURN TRUE;
END IF;
END
$func$;
The function takes a table name and the query string, and optionally also a schema to create the table in (defaults to the current schema).
Note the correct use of =
in the function header and :=
in the function body:
- The forgotten assignment operator "=" and the commonplace ":="
Also note how identifiers are escaped as identifiers. You can't use regclass
, since the table does not exist, yet:
- Table name as a PostgreSQL function parameter
CREATE TABLE AS is considered a separate statement from a normal CREATE TABLE, and until Postgres version 9.5 (see changelog entry) didn't support an IF NOT EXISTS
clause. (Be sure to look at the correct version of the manual for the version you are using.)
Although not quite as flexible, the CREATE TABLE ... LIKE
syntax might be an alternative in some situations; rather than taking its structure (and content) from a SELECT
statement, it copies the structure of another table or view.
Consequently, you could write something like this (untested); the final insert is a rather messy way of doing nothing if the table is already populated:
CREATE OR REPLACE VIEW source_data AS SELECT * FROM foo NATURAL JOIN bar;
CREATE TABLE IF NOT EXISTS snapshot LIKE source_data;
INSERT INTO snapshot
SELECT * FROM source_data
WHERE NOT EXISTS ( SELECT * FROM snapshot );
Alternatively, if you want to discard previous data (e.g. an abandoned temporary table), you could conditionally drop the old table, and unconditionally create the new one:
DROP TABLE IF EXISTS temp_stuff;
CREATE TEMPORARY TABLE temp_stuff AS SELECT * FROM foo NATURAL JOIN bar;