Answers:
这是使用“ DO”语句的简短版本:
DO $$
BEGIN
BEGIN
ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
END;
END;
$$
您不能将它们作为参数传递,您需要在客户端的字符串中进行变量替换,但这是一个自包含的查询,如果该列已经存在,则仅发出一条消息;如果不存在,则添加该消息,并且会因其他错误(例如无效的数据类型)而继续失败。
如果这些方法是来自外部来源的随机字符串,则我不建议使用任何这些方法。无论使用哪种方法(作为查询执行的服务器端或服务器端动态字符串),由于它使您容易受到SQL注入攻击,因此这将是灾难的根源。
DO $$
失败。我也尝试DO $$;
过失败,直到我刚刚开始DO $$DECLARE r record;
在dev postgres docs上的示例中给出的代码块为止。
END; $$
是语法错误(Postgres 9.3),我不得不END $$;
改用
EXCEPTION
)较为通用,可以用于没有IF NOT EXISTS
语法的任务-例如ALTER TABLE ... ADD CONSTRAINT
。
使用Postgres 9.6可以使用if not exists
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
ADD CONSTRAINT IF NOT EXISTS
。
CREATE OR REPLACE function f_add_col(_tbl regclass, _col text, _type regtype)
RETURNS bool AS
$func$
BEGIN
IF EXISTS (SELECT 1 FROM pg_attribute
WHERE attrelid = _tbl
AND attname = _col
AND NOT attisdropped) THEN
RETURN FALSE;
ELSE
EXECUTE format('ALTER TABLE %s ADD COLUMN %I %s', _tbl, _col, _type);
RETURN TRUE;
END IF;
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT f_add_col('public.kat', 'pfad1', 'int');
返回TRUE
成功,否则FALSE
(列已存在)。
为无效的表或类型名称引发异常。
这可以通过一条DO
语句来完成,但是DO
语句不能返回任何内容。如果要重复使用,我将创建一个函数。
我用的对象标识符类型 regclass
和regtype
用于_tbl
和_type
其中a)防止SQL注入和b)立即两者的检查有效性(最便宜的可能的方式)。列名_col
仍然被用于消毒EXECUTE
用quote_ident()
。此相关答案中的更多说明:
format()
需要Postgres 9.1+。对于较旧的版本,请手动进行串联:
EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;
您可以对表名进行模式限定,但是不必这样做。
您可以在函数调用中对标识符加双引号以保留驼峰式和保留字(但无论如何您都不应使用其中的任何一种)。
我查询pg_catalog
而不是information_schema
。详细说明:
提示:与没有
EXCEPTION
子句的块相比,包含子句的块的进入和退出成本明显更高。因此,不要使用EXCEPTION
而无需使用。
DO
声明,可以稍加修改即可接受,DEFAULT
并且效果很好!
选择查询之后将true/false
使用EXISTS()
函数返回。
EXISTS():EXISTS
的参数是任意的SELECT语句或子查询。计算子查询以确定是否返回任何行。如果返回至少一行,则EXISTS的结果为“ true”;如果子查询不返回任何行,则EXISTS的结果为“ false”
SELECT EXISTS(SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'x'
AND column_name = 'y');
并使用以下动态SQL语句更改表
DO
$$
BEGIN
IF NOT EXISTS (SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'x'
AND column_name = 'y') THEN
ALTER TABLE x ADD COLUMN y int DEFAULT NULL;
ELSE
RAISE NOTICE 'Already exists';
END IF;
END
$$
下面的函数将检查该列是否存在,并返回适当的消息,否则它将将该列添加到表中。
create or replace function addcol(schemaname varchar, tablename varchar, colname varchar, coltype varchar)
returns varchar
language 'plpgsql'
as
$$
declare
col_name varchar ;
begin
execute 'select column_name from information_schema.columns where table_schema = ' ||
quote_literal(schemaname)||' and table_name='|| quote_literal(tablename) || ' and column_name= '|| quote_literal(colname)
into col_name ;
raise info ' the val : % ', col_name;
if(col_name is null ) then
col_name := colname;
execute 'alter table ' ||schemaname|| '.'|| tablename || ' add column '|| colname || ' ' || coltype;
else
col_name := colname ||' Already exist';
end if;
return col_name;
end;
$$
基本上,这是sola的解决方案,但只是进行了一些整理。足够不同的是,我不只是想“改进”他的解决方案(而且,我认为这很粗鲁)。
主要区别在于它使用EXECUTE格式。我认为这更干净一些,但是我认为您必须使用PostgresSQL 9.1或更高版本。
这已经在9.1上进行了测试并且可以工作。注意:如果schema / table_name /或data_type无效,则会引发错误。那可以“解决”,但在许多情况下可能是正确的行为。
CREATE OR REPLACE FUNCTION add_column(schema_name TEXT, table_name TEXT,
column_name TEXT, data_type TEXT)
RETURNS BOOLEAN
AS
$BODY$
DECLARE
_tmp text;
BEGIN
EXECUTE format('SELECT COLUMN_NAME FROM information_schema.columns WHERE
table_schema=%L
AND table_name=%L
AND column_name=%L', schema_name, table_name, column_name)
INTO _tmp;
IF _tmp IS NOT NULL THEN
RAISE NOTICE 'Column % already exists in %.%', column_name, schema_name, table_name;
RETURN FALSE;
END IF;
EXECUTE format('ALTER TABLE %I.%I ADD COLUMN %I %s;', schema_name, table_name, column_name, data_type);
RAISE NOTICE 'Column % added to %.%', column_name, schema_name, table_name;
RETURN TRUE;
END;
$BODY$
LANGUAGE 'plpgsql';
用法:
select add_column('public', 'foo', 'bar', 'varchar(30)');
可以添加到迁移脚本调用函数中,完成后删除。
create or replace function patch_column() returns void as
$$
begin
if exists (
select * from information_schema.columns
where table_name='my_table'
and column_name='missing_col'
)
then
raise notice 'missing_col already exists';
else
alter table my_table
add column missing_col varchar;
end if;
end;
$$ language plpgsql;
select patch_column();
drop function if exists patch_column();
就我而言,由于其创建原因,我们的迁移脚本很难跨越不同的架构。
要解决此问题,我们使用了一个仅捕获并忽略该错误的异常。这也带来了很好的副作用,即易于查看。
但是,请警惕其他解决方案具有其自身优势,而这些优势可能会超过该解决方案:
DO $$
BEGIN
BEGIN
ALTER TABLE IF EXISTS bobby_tables RENAME COLUMN "dckx" TO "xkcd";
EXCEPTION
WHEN undefined_column THEN RAISE NOTICE 'Column was already renamed';
END;
END $$;
您可以按照以下方式进行操作。
ALTER TABLE tableName drop column if exists columnName;
ALTER TABLE tableName ADD COLUMN columnName character varying(8);
因此,如果该列已经存在,它将删除该列。然后将列添加到特定的表。
只需检查查询是否返回column_name。
如果没有,请执行以下操作:
ALTER TABLE x ADD COLUMN y int;
在哪里放置了对“ x”和“ y”有用的东西,以及在我使用int的地方当然是合适的数据类型。
DO $$ BEGIN BEGIN CREATE INDEX type_idx ON table1 USING btree (type); EXCEPTION WHEN duplicate_table THEN RAISE NOTICE 'Index exists.'; END; END;$$;
同样的方法CREATE INDEX
;)谢谢您的回答