如果在PostgreSQL上不存在列,如何添加列?

时间:2012-09-26 08:20:30

标签: postgresql postgresql-9.1

问题很简单。如何将列x添加到表y,但仅当x列不存在时?我发现只有解决方案here如何检查列是否存在。

SELECT column_name 
FROM information_schema.columns 
WHERE table_name='x' and column_name='y';

11 个答案:

答案 0 :(得分:226)

Postgres 9.6可以使用选项if not exists

完成此操作
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;

答案 1 :(得分:115)

这是一个使用“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;
$$

你不能将这些作为参数传递,你需要在客户端的字符串中进行变量替换,但这是一个自包含的查询,只有在列已经存在的情况下才会发出消息,如果它不存在则添加并且将继续在其他错误(如无效数据类型)上失败。

如果这些方法是来自外部源的随机字符串,我建议不要执行这些方法。无论你使用什么方法(作为查询执行的cleint端或服务器端动态字符串),它都会成为灾难的一种方法,因为它会让你开始SQL注入攻击。

答案 2 :(得分:19)

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语句不能返回任何内容。如果是重复使用,我会创建一个函数。

  • 我使用object identifier types regclassregtype代表_tbl_type a)防止SQL注入和b)检查两者的有效性立即(最便宜的方式)。仍需要使用_colEXECUTE的列名称quote_ident()进行清理。在这个相关答案中有更多解释:

  • format()需要Postgres 9.1+。对于旧版本手动连接:

    EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;
    
  • 您可以对表名进行架构限定,但您不必这样做。
    你可以在函数调用中双引号标识符以保留camel-case和保留字(但你不应该使用任何这些)。

  • 我查询pg_catalog而不是information_schema。详细解释:

  • 包含像the currently accepted answer这样的EXCEPTION子句的块要慢得多。这通常更简单,更快捷。 The documentation:

  

提示:包含EXCEPTION子句的块明显更多   进入和退出比没有一个的块贵。所以,不要   

答案 3 :(得分:16)

以下选择查询将使用EXISTS()函数返回true/false

  

EXISTS()
EXISTS的参数是一个任意的SELECT语句,或者   子查询。对子查询进行评估以确定它是否返回   任何行。如果它至少返回一行,则EXISTS的结果为   “真正”;如果子查询没有返回任何行,则EXISTS的结果为   “假”

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

答案 4 :(得分:2)

对于使用Postgre 9.5+的用户(我相信大多数人都这样做),有一个非常简单干净的解决方案

ALTER TABLE if exists <tablename> add if not exists <columnname> <columntype>

答案 5 :(得分:1)

下面的函数将检查列是否存在返回适当的消息,否则它会将列添加到表中。

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

答案 6 :(得分:1)

这基本上是来自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)');

答案 7 :(得分:0)

可以添加到迁移脚本调用函数并在完成后删除。

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();

答案 8 :(得分:0)

您可以通过以下方式完成。

ALTER TABLE tableName drop column if exists columnName; 
ALTER TABLE tableName ADD COLUMN columnName character varying(8);

因此,如果列已经存在,它将删除该列。然后将列添加到特定表。

答案 9 :(得分:0)

就我而言,由于它是如何创建的,所以我们的迁移脚本很难跨越不同的模式。

要解决此问题,我们使用了一个仅捕获并忽略该错误的异常。这也带来了很好的副作用,那就是易于查看。

但是,请警惕其他解决方案具有自己的优势,而这些优势可能会超过该解决方案:

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

答案 10 :(得分:-4)

只需检查查询是否返回了column_name。

如果没有,请执行以下操作:

ALTER TABLE x ADD COLUMN y int;

你为'x'和'y'放置一些有用的东西,当然还有一个合适的数据类型,我用的是int。