PostgreSQL створює таблицю, якщо її немає


175

У сценарії MySQL ви можете писати:

CREATE TABLE IF NOT EXISTS foo ...;

... інші речі ...

і тоді ви можете запустити сценарій багато разів, не створюючи таблиці.

Як це зробити в PostgreSQL?

Відповіді:


279

Ця функція була реалізована в 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для цієї функції та зробити її власником іншої ролі з необхідними привілеями. Ця версія досить безпечна.


Мене змушують використовувати існуючу базу даних postgres 8.4. Цей хак робить трюк, дякую!
Безмежний

1
@Boundless: я бачив, що вашу редакцію відхилено як "занадто незначну". Я застосував це, бо це не зашкодить. Однак вам слід виконати CREATE FUNCTIONлише один раз. Це те, SELECT create_mytable();що ви можете хотіти телефонувати багато разів.
Ервін Брандстеттер

1
Брандстетер: Я з вами згоден. Проблема, з якою я зіткнувся, полягала в тому, що я не знала, була створена функція чи ні (подібно до того, як таблиця може існувати чи не може існувати). Тому я хочу переконатися, що функція створена, перш ніж я її закликаю.
Безмежний

83

Спробуйте це:

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

це насправді більш чисте рішення. повинні бути відхилені.
SDReyes

4
насправді я жахнувся, скільки існує рішень із функцією «функція».
SDReyes

8
@SDReyes ці інші рішення були розміщені до Postgres 9.1, який включав IF NOT EXISTSопцію.
Кріс

2
Не впевнений, як ця відповідь сприяла, як відповідь @ erwin-marketetter була повна сама по собі.
комюнітор

@comiventor правильний, це робить, як ніколи показує, що використання параметра є. Провідну відповідь я не помітив, що поки не побачив цього. Це трохи допомагає.
Сердитий 84

8

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

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

Далі можна буде спростити взяти лише один параметр, якщо вилучити назву таблиці з параметра запиту. Також я пропустив схеми.


3

Це рішення дещо схоже на відповідь Ервіна Брандштеттера, але він використовує лише мову sql.

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

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

Це рішення натхнене публікацією Андреаса Шербаума .

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

Ваше рішення є чудовим, навіть коли plpgsql доступний. Це легко розширюється для створення поглядів і функцій на об'єктах, які не існують в даний момент часу. Наприклад, перегляди таблиць з іноземних серверів. Ти врятував мій день! Дякую!
Алекс Ю.

3

СТВОРИТИ ТАБЛИЦІ, ЯКЩО НЕ існує ... Але для цього можна написати просту процедуру, наприклад:

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;

3

СТВОРИТИ ТАБЛИЦІ, ЯКЩО НЕ існує ... Але для цього можна написати просту процедуру, наприклад:

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

всередині тригера не завжди працює: gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45 ПОМИЛКА: відношення "foo" вже існує
igilfanov
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.