问题很简单。如何添加列x到表y,但只有当x列不存在?我发现唯一的解决方案在这里如何检查列是否存在。
SELECT column_name
FROM information_schema.columns
WHERE table_name='x' and column_name='y';
问题很简单。如何添加列x到表y,但只有当x列不存在?我发现唯一的解决方案在这里如何检查列是否存在。
SELECT column_name
FROM information_schema.columns
WHERE table_name='x' and column_name='y';
当前回答
Postgres 9.6新增ALTER TABLE tbl ADD COLUMN IF NOT EXISTS column_name。 所以这已经过时了。您可以在较旧的版本或变体中使用它来检查列名以外的其他内容。
CREATE OR REPLACE function f_add_col(_tbl regclass, _col text, _type regtype)
RETURNS bool
LANGUAGE plpgsql AS
$func$
BEGIN
IF EXISTS (SELECT 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$;
电话:
SELECT f_add_col('public.kat', 'pfad1', 'int');
成功返回true,否则返回false(列已经存在)。 对于无效的表名或类型名引发异常。
为什么是另一个版本?
This could be done with a DO statement, but DO statements cannot return anything. And if it's for repeated use, I would create a function. I use the object identifier types regclass and regtype for _tbl and _type which a) prevents SQL injection and b) checks validity of both immediately (cheapest possible way). The column name _col has still to be sanitized for EXECUTE with quote_ident(). See: Table name as a PostgreSQL function parameter format() requires Postgres 9.1+. For older versions concatenate manually: EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type; You can schema-qualify your table name, but you don't have to. You can double-quote the identifiers in the function call to preserve camel-case and reserved words (but you shouldn't use any of this anyway). I query pg_catalog instead of the information_schema. Detailed explanation: How to check if a table exists in a given schema Blocks containing an EXCEPTION clause are substantially slower. This is simpler and faster. The manual:
提示 包含EXCEPTION子句的块要多得多 进出的成本比一个没有的街区要高。 因此,如果没有必要,不要使用EXCEPTION。
其他回答
这基本上是从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)');
Postgres 9.6新增ALTER TABLE tbl ADD COLUMN IF NOT EXISTS column_name。 所以这已经过时了。您可以在较旧的版本或变体中使用它来检查列名以外的其他内容。
CREATE OR REPLACE function f_add_col(_tbl regclass, _col text, _type regtype)
RETURNS bool
LANGUAGE plpgsql AS
$func$
BEGIN
IF EXISTS (SELECT 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$;
电话:
SELECT f_add_col('public.kat', 'pfad1', 'int');
成功返回true,否则返回false(列已经存在)。 对于无效的表名或类型名引发异常。
为什么是另一个版本?
This could be done with a DO statement, but DO statements cannot return anything. And if it's for repeated use, I would create a function. I use the object identifier types regclass and regtype for _tbl and _type which a) prevents SQL injection and b) checks validity of both immediately (cheapest possible way). The column name _col has still to be sanitized for EXECUTE with quote_ident(). See: Table name as a PostgreSQL function parameter format() requires Postgres 9.1+. For older versions concatenate manually: EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type; You can schema-qualify your table name, but you don't have to. You can double-quote the identifiers in the function call to preserve camel-case and reserved words (but you shouldn't use any of this anyway). I query pg_catalog instead of the information_schema. Detailed explanation: How to check if a table exists in a given schema Blocks containing an EXCEPTION clause are substantially slower. This is simpler and faster. The manual:
提示 包含EXCEPTION子句的块要多得多 进出的成本比一个没有的街区要高。 因此,如果没有必要,不要使用EXCEPTION。
下面是使用“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注入攻击。
在Postgres 9.6中,如果这个选项不存在,可以使用它来实现
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
可以添加到迁移脚本调用函数,并在完成时删除。
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();