Tạo bảng PostgreSQL nếu không tồn tại


173

Trong tập lệnh MySQL, bạn có thể viết:

CREATE TABLE IF NOT EXISTS foo ...;

... những thứ khác ...

và sau đó bạn có thể chạy tập lệnh nhiều lần mà không cần tạo lại bảng.

Làm thế nào để bạn làm điều này trong PostgreSQL?

Câu trả lời:


277

Tính năng này đã được triển khai trong Postgres 9.1 :

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



Đối với các phiên bản cũ hơn , đây là một chức năng để làm việc xung quanh nó:

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;

Gọi:

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

Ghi chú:


Tôi đang bị buộc phải sử dụng cơ sở dữ liệu postgres 8.4 hiện có. Hack này thực hiện các mẹo, cảm ơn bạn!
Vô biên

1
@Boundless: Tôi thấy rằng chỉnh sửa của bạn đã bị từ chối là "quá nhỏ". Tôi đã áp dụng nó, bởi vì nó sẽ không bị tổn thương. Tuy nhiên, bạn chỉ nên thực hiện CREATE FUNCTIONmột lần. Đó là SELECT create_mytable();bạn có thể muốn gọi nhiều lần.
Erwin Brandstetter

1
Brandstetter: Tôi đồng ý với bạn. Vấn đề mà tôi gặp phải là tôi không biết hàm có được tạo hay không (giống như bảng có thể tồn tại hoặc không tồn tại). Vì vậy, tôi muốn đảm bảo chức năng được tạo trước khi tôi gọi nó.
Vô biên

81

Thử cái này:

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

Đây thực sự là giải pháp sạch hơn. nên được nâng cao.
SDReyes

4
thực tế, tôi lo sợ có bao nhiêu giải pháp liên quan đến "chức năng".
SDReyes

8
@SDReyes những giải pháp khác đã được đăng trước Postgres 9.1 bao gồm IF NOT EXISTStùy chọn.
Kris

2
Không chắc câu trả lời này đã đóng góp như thế nào khi câu trả lời @ erwin-brandstetter đã hoàn thành.
diễn viên

@comiventor đúng, cái này thực hiện bao giờ cho thấy việc sử dụng tham số là. Câu trả lời hàng đầu tôi không phát hiện ra cho đến khi tôi thấy cái này. Điều này không giúp một chút.
Tức giận 84

7

Tôi đã tạo một giải pháp chung từ các câu trả lời hiện có có thể được sử dụng lại cho bất kỳ bảng nào:

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;

Sử dụng:

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

Có thể đơn giản hóa hơn nữa chỉ lấy một tham số nếu ai đó trích xuất tên bảng ra khỏi tham số truy vấn. Ngoài ra tôi rời khỏi các lược đồ.


2

Giải pháp này có phần giống với câu trả lời của Erwin Brandstetter, nhưng chỉ sử dụng ngôn ngữ sql.

Theo mặc định, không phải tất cả các bản cài đặt PostgreSQL đều có ngôn ngữ plpqsql, điều này có nghĩa là bạn có thể phải gọi CREATE LANGUAGE plpgsqltrước khi tạo hàm và sau đó phải xóa ngôn ngữ một lần nữa, để cơ sở dữ liệu ở trạng thái như trước (nhưng chỉ khi cơ sở dữ liệu không có ngôn ngữ plpgsql để bắt đầu). Xem sự phức tạp tăng trưởng như thế nào?

Việc thêm plpgsql có thể không thành vấn đề nếu bạn đang chạy tập lệnh cục bộ, tuy nhiên, nếu tập lệnh được sử dụng để thiết lập lược đồ tại khách hàng, có thể không muốn để lại các thay đổi như thế này trong cơ sở dữ liệu khách hàng.

Giải pháp này được lấy cảm hứng từ một bài đăng của 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();

Giải pháp của bạn là tuyệt vời ngay cả khi plpgsql có sẵn. Có thể dễ dàng mở rộng để tạo các chế độ xem và chức năng trên các đối tượng không tồn tại tại thời điểm đó. Ví dụ: lượt xem trên các bảng từ máy chủ nước ngoài. Bạn đã cứu ngày của tôi! Cảm ơn!
Alex Yu

2

Không có BẢNG TẠO NẾU KHÔNG HIỆN TẠI ... nhưng bạn có thể viết một thủ tục đơn giản cho việc đó, đại loại như:

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;

2

Không có BẢNG TẠO NẾU KHÔNG HIỆN TẠI ... nhưng bạn có thể viết một thủ tục đơn giản cho việc đó, đại loại như:

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

bên trong một trình kích hoạt không phải lúc nào cũng hoạt động: gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45 LRI : mối quan hệ "foo" đã tồn tại
igilfanov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.