问题很简单。如何添加列x到表y,但只有当x列不存在?我发现唯一的解决方案在这里如何检查列是否存在。

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

当前回答

在我的例子中,由于创建它的原因,我们的迁移脚本跨越不同的模式有点困难。

为了解决这个问题,我们使用了一个异常,它只是捕获并忽略了错误。这也有一个很好的副作用,就是更容易观察。

然而,要注意,其他解决方案都有自己的优势,可能会超过这个解决方案:

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

其他回答

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

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

这基本上是从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 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;
$$

在Postgres 9.6中,如果这个选项不存在,可以使用它来实现

ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;

下面的选择查询将返回true/false,使用EXISTS()函数。

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