PostgreSQL:如果不存在则创建表 AS

Posted

技术标签:

【中文标题】PostgreSQL:如果不存在则创建表 AS【英文标题】:PostgreSQL: Create table if not exists 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"

有什么办法吗?

【问题讨论】:

【参考方案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 中添加。见:

PostgreSQL create table if not exists

Postgres 9.0 或更早版本

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

How to check if a table exists in a given schema
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)。

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

The forgotten assignment operator "=" and the commonplace ":="

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

Table name as a PostgreSQL function parameter

【讨论】:

【参考方案4】:

很简单:

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

【讨论】:

通常最好解释一个解决方案,而不是仅仅发布一些匿名代码行。你可以阅读How do I write a good answer,也可以阅读Explaining entirely code-based answers 发帖者询问的是create table as 而不是create table。对于create table,是的,支持if not exists【参考方案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;

【讨论】:

以上是关于PostgreSQL:如果不存在则创建表 AS的主要内容,如果未能解决你的问题,请参考以下文章

如果条目不存在,则使用 PostgreSQL 进行多次插入

postgresql:如果不退出则创建用户[重复]

postgresql----数据库表约束----UNIQUE

如果存在则更改表,如果不存在则创建

MYSQL:如果不存在则创建表

如果 Oracle 中不存在表,则创建一个表(使用 Java)