В MySQL script вы можете написать:
CREATE TABLE IF NOT EXISTS foo ...;
... другие вещи...
а затем вы можете многократно запускать script без повторного создания таблицы.
Как вы это делаете в PostgreSQL?
В MySQL script вы можете написать:
CREATE TABLE IF NOT EXISTS foo ...;
... другие вещи...
а затем вы можете многократно запускать script без повторного создания таблицы.
Как вы это делаете в PostgreSQL?
Эта функция была реализована в Postgres 9.1:
CREATE TABLE IF NOT EXISTS myschema.mytable (i integer);
Для более старых версий здесь есть функция, позволяющая обойти это:
CREATE OR REPLACE FUNCTION create_mytable ()
RETURNS void 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$ LANGUAGE plpgsql;
вызова:
SELECT create_mytable(); -- call as many times as you want.
Примечание:
Столбцы schemaname
и tablename
в pg_tables
чувствительны к регистру. Если вы используете двойные кавычки идентификаторов в операторе CREATE TABLE
, вам нужно использовать точно такое же написание. Если вы этого не сделаете, вам нужно использовать строчные буквы. См:
pg_tables
содержит только фактические таблицы. Идентификатор все еще может быть занят связанными объектами. См:
Если роль, выполняющая эту функцию, не обладает необходимыми привилегиями для создания таблицы, вы можете использовать SECURITY DEFINER
для этой функции и сделать ее принадлежащей другой роли с необходимыми привилегиями. Эта версия достаточно безопасна.
Попробуйте следующее:
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 (user_id)
)
Я создал общее решение из существующих ответов, которое можно использовать повторно для любой таблицы:
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;
Использование:
select create_if_not_exists('my_table', 'CREATE TABLE my_table (id integer NOT NULL);');
Далее можно было бы упростить принятие только одного параметра, если бы извлечь имя таблицы из параметра запроса. Также я не учитывал схемы. Не стесняйтесь распространять свое решение, если вы знаете, как это сделать - я еще не настолько глубоко в plpgsql (это первый раз, когда я с ним разбираюсь).
CREATE TABLE, ЕСЛИ НЕ СУЩЕСТВУЕТ... нет, но вы можете написать для этого простую процедуру, например:
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'
);
Нет CREATE TABLE, ЕСЛИ НЕ СУЩЕСТВУЕТ... но вы можете написать простую процедуру для этого, например:
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;
Это решение несколько похоже на ответ Эрвина Брандстретера, но использует только язык sql.
Не все установки PostgreSQL имеют язык plpqsql по умолчанию, это означает, что вам может потребоваться вызвать CREATE LANGUAGE plpgsql
перед созданием функции, а затем снова удалить язык, чтобы оставить базу данных в том же состоянии, что и раньше (но только если база данных не имела языка plpgsql для начала). Посмотрите, как растет сложность?
Добавление plpgsql может не возникнуть, если вы используете локальный script локально, однако, если script используется для настройки схемы у клиента, может быть нежелательно оставлять такие изменения в базе данных клиентов.
Это решение вдохновлено сообщение Андреаса Шербаума.
-- 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();