2009-11-19 2 views
81

В сценарии MySQL вы можете написать:PostgreSQL создать таблицу, если не существует

CREATE TABLE IF NOT EXISTS foo ...; 

... другие вещи ...

, а затем вы можете запустить сценарий много раз без повторного создания Таблица.

Как вы это делаете в PostgreSQL?

+0

@ErwinBrandstetter: Это может привести к возобновлению очень старого потока без какой-либо цели, но ссылка, которую вы указали, указывает на эту же страницу. –

ответ

1

Там нет CREATE TABLE IF NOT EXISTS ... но вы можете написать простую процедуру для того, что-то вроде:

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' 
); 

Это немного странно, но может быть просто

+0

внутри триггера не всегда работает: https://gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45 ОШИБКА: отношение «foo» уже существует – igilfanov

117

Этот функция была implemented in 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 1 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. 

Если пользователь не имеет необходимые привилегии для создания таблицы вы могли бы хотите использовать SECURITY DEFINER. Эта версия достаточно безопасна.

+0

Я вынужден использовать существующую базу данных postgres 8.4. Это взломать трюк, спасибо! – Boundless

+0

@Boundless: Я видел, что ваше редактирование было отклонено как «слишком незначительное». Я применил его, потому что это не повредит. Однако вы должны выполнить 'CREATE FUNCTION' только один раз. Это 'SELECT create_mytable();', который вы можете вызвать много раз. –

+0

Brandstetter: Я согласен с вами. Проблема, с которой я столкнулась, заключалась в том, что я не знал, была ли эта функция создана или нет (так же, как эта таблица может существовать или не существовать). Поэтому я хочу убедиться, что функция создана до того, как я ее вызову. – Boundless

5

Я создал общее решение из существующих ответов, которые могут быть повторно использованы для любой таблицы:

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 (это первый раз, когда я с ним разбираюсь).

1

Это решение несколько похоже на ответ Эрвина Брандстретера, но использует только язык sql.

Не все установки PostgreSQL имеют язык plpqsql по умолчанию, это означает, что вам нужно будет позвонить CREATE LANGUAGE plpgsql перед созданием функции, а затем снова удалить язык, чтобы оставить базу данных в том же состоянии, что и раньше (но только если у базы данных не было языка plpgsql для начала). Посмотрите, как растет сложность?

Добавление plpgsql может не возникнуть, если вы используете локальный скрипт, однако, если скрипт используется для настройки схемы у клиента, может быть нежелательно оставлять такие изменения в базе данных клиентов.

Это решение вдохновлено 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(); 
23

Попробуйте это:

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) 
) 
+0

это на самом деле чище решение. должно быть поддержано. – SDReyes

+2

На самом деле, я боюсь, сколько решений связано с «функцией». – SDReyes

+4

@SDReyes Другие решения были опубликованы до Postgres 9.1, которые включали опцию 'IF NOT EXISTS'. – Kris

1

Там это не CREATE TABLE IF NOT EXISTS ... но вы можете написать простую процедуру для того, что-то вроде:

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; 
Смежные вопросы