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

36

我正在使用PostgreSQL, 我是一个SQL初学者。我试图从查询结果创建一张表,如果我运行:

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

它运行得很好。但如果我添加'if not exists'并运行:

它仍然会正常工作。


Translated: "It works just fine. But then if I add 'if not exists' and run: It still works as expected."
CREATE TABLE IF NOT EXISTS table_name AS
   (....query...)

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

ERROR: syntax error at or near "as"
有没有办法做到这一点?
6个回答

36

CREATE TABLE AS 语句与普通的CREATE TABLE语句是不同的。在Postgres版本9.5之前(请注意查看您使用的版本的正确指南),它不支持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;

我会尝试你的建议。谢谢 - 我很感激。 - user3591836
1
如果您要创建一个VIEW以复制表结构,那么您可以选择使用**MATERIALIZED VIEW**。 - Erwin Brandstetter
@ErwinBrandstetter 嗯,没错。除了不能接受 IF NOT EXISTS 子句之外;你可以使用 DROP MATERIALISED VIEW IF EXISTS。不过,如果不知道确切的用例,很难知道这些选项是否真正相关。 - IMSoP
@ErwinBrandstetter请具体说明支持_feature_的PostgreSQL版本,因为MATERIALIZED VIEW支持PostgreSQL 9.3及以上版本 - Vivek S.
在至少版本9.3中,LIKE source_data 部分需要用括号括起来,否则该行代码将无法执行。 - Dylan
显示剩余4条评论

7

CREATE TABLE IF NOT EXISTS ...在Postgres 9.1中添加。详情请参见:

Postgres 9.0或更早版本

如果您要编写此功能,请基于系统目录表pg_class,而不是基于信息模式统计收集器中的视图(仅在激活时存在)。

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

该函数接受表名和查询字符串,还可以选择在其中创建表格的模式(默认为当前模式)。
请注意函数头中=的正确使用和函数体中:=的常见用法: 此外,请注意如何将标识符转义为标识符。 由于表尚不存在,因此无法使用regclass

0

使用 do:

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


0

试试这个,

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 

函数中有几个薄弱点。对于一个注释来说太多了,我添加了另一个答案。 - Erwin Brandstetter

0

很简单:

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

通常最好解释一下解决方案,而不仅仅是发布一些匿名代码行。您可以阅读《如何撰写良好的答案》和《解释完全基于代码的答案》。 - Anh Pham
海报询问了关于“create table as”而不是“create table”的问题。对于“create table”,是的,“if not exists”被支持。 - SimonInNYC

0

针对REDSHIFT PLPGSQL风格的CTAS(创建表作为)操作。感谢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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接