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 中添加。见:
Postgres 9.0 或更早版本
如果您要为此编写函数,请将其基于system catalog table pg_class
,而不是基于information schema 或statistics 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)
【讨论】:
通常最好解释一个解决方案,而不是仅仅发布一些匿名代码行。你可以阅读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的主要内容,如果未能解决你的问题,请参考以下文章