【问题标题】:PostgreSQL: Create table if not exists ASPostgreSQL:如果不存在则创建表 AS
【发布时间】:2014-11-11 20:38:27
【问题描述】:

我正在使用 PostgreSQL,并且是一名 SQL 初学者。我正在尝试从查询中创建一个表,如果我运行:

CREATE TABLE table_name AS
   (....query...)

它工作得很好。但是,如果我添加“如果不存在”并运行:

CREATE TABLE IF NOT EXISTS table_name AS
   (....query...)

使用完全相同的查询,我得到:

ERROR: syntax error at or near "as"

有什么办法吗?

【问题讨论】:

    标签: sql postgresql create-table


    【解决方案1】:

    CREATE TABLE AS 被视为与普通 CREATE TABLE 不同的语句,并且直到 Postgres 9.5 版(请参阅 changelog entry)不支持 IF NOT EXISTS 子句。 (请务必查看您正在使用的版本的正确版本的手册。)

    虽然不够灵活,但CREATE TABLE ... LIKE 语法在某些情况下可能是一种替代方案;它不是从SELECT 语句中获取其结构(和内容),而是复制另一个表或视图的结构。

    因此,您可以编写类似这样的内容(未经测试);如果表已经被填充,那么最后的插入是一种相当混乱的方式:

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

    或者,如果您想丢弃以前的数据(例如废弃的临时表),您可以有条件地删除旧表,并无条件地创建新表:

    DROP TABLE IF EXISTS temp_stuff;
    
    CREATE TEMPORARY TABLE temp_stuff AS SELECT * FROM foo NATURAL JOIN bar;
    

    【讨论】:

    • 我会考虑你的建议。谢谢 - 我很感激。
    • 如果您要创建VIEW 来复制表结构,您可能会一直使用MATERIALIZED VIEW
    • @ErwinBrandstetter 嗯,这是真的。除了那也不接受IF NOT EXISTS 子句;不过你可以DROP MATERIALISED VIEW IF EXISTS。在不知道确切的用例的情况下,很难知道这些选项中的任何一个是否真的相关。
    • @ErwinBrandstetter 具体在支持功能PostgreSQL version,因为MATERIALIZED VIEW支持PostgreSQL version 9.3及以上
    • @WingedPanther:正确。对于不想声明实际使用的版本的问题,我倾向于假设 Postgres 的当前版本。
    【解决方案2】:

    试试这个,

    create or replace function create_table(tblname text) returns text as
    $$ 
    BEGIN
    $1 = trim($1);
    IF not EXISTS (select relname from pg_stat_user_tables where relname =$1) THEN
    execute 'create table '||$1||' as select * from tbl'; -- <put your query here>
    return ''||$1||' Created Successfully !!';
    else
    return  ''||$1||' Already Exists !!';
    END IF;
    END
    $$
    language plpgsql 
    

    create or replace function create_table_qry(tblname text,qry text) returns text as
    $$ 
    BEGIN
    $1 = trim($1);
    IF not EXISTS (select relname from pg_stat_user_tables where relname =$1) THEN
    execute 'create table '||$1||' as '||$2||'';
    return ''||$1||' Created Successfully !!';
    else
    return  ''||$1||' Already Exists !!';
    END IF;
    END
    $$
    language plpgsql 
    

    【讨论】:

    • 这个函数有几个弱点。为了发表评论,我添加了另一个答案。
    【解决方案3】:

    CREATE TABLE IF NOT EXISTS ... 在 Postgres 9.1 中添加。见:

    Postgres 9.0 或更早版本

    如果您要为此编写函数,请将其基于system catalog table pg_class,而不是基于information schemastatistics collector 中的视图(仅在激活时才存在)。

    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$;
    

    该函数采用表名和查询字符串,还可以选择在其中创建表的架构(默认为current schema)。

    注意函数头中=和函数体中:=的正确使用:

    还要注意标识符是如何转义为标识符的。你不能使用regclass,因为该表还不存在:

    【讨论】:

      【解决方案4】:

      很简单:

       CREATE TABLE IF NOT EXISTS abc ( sql_id BIGINT(20) NOT NULL
         AUTO_INCREMENT PRIMARY KEY, sender VARCHAR(20) NULL)
      

      【讨论】:

      【解决方案5】:

      使用做:

      do $$ begin
      
      if not exists (  SELECT 1
         FROM   information_schema.tables 
         WHERE  table_schema = 'schema_name'
         AND    table_name = 'bla ') then
      
        create table schema_name.bla as select * from blu;
      end if;
      
      end $$;
      
      

      【讨论】:

        【解决方案6】:

        CTAS(创建表 AS),用于 REDSHIFT PLPGSQL 风格。向Erwin Brandstetter 喊出使用纯 PG 语法的根本思想。

        CREATE
        OR
        REPLACE
        PROCEDURE pipeline.sp_create_table_if_not_exists_as (sch VARCHAR, tbl VARCHAR, qry VARCHAR, tbl_attrs VARCHAR)
         AS
            /*
             specifically an exception for CTAS functionality: https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_AS.html
            */
        $$
        BEGIN
        
        IF EXISTS (
           SELECT 1
           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 INFO 'Table already exists: %.%', sch, tbl;
        ELSE
            EXECUTE 'CREATE TABLE ' || sch || '.' || tbl || ' ' || tbl_attrs || ' AS ' || qry;
            RAISE INFO 'Table created successfully: %.%, using query: [%], optional attributes: [%]', sch, tbl, qry, tbl_attrs;
        END IF;
        
        END;
        $$
        language plpgsql;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-26
          • 1970-01-01
          • 2010-12-03
          • 2013-05-26
          • 1970-01-01
          • 2010-09-19
          • 1970-01-01
          相关资源
          最近更新 更多