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

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

当前回答

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

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

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注入攻击。

你可以这样做。

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

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

对于那些使用Postgre 9.5+的人(我相信你们大多数人都在使用),有一个非常简单和干净的解决方案

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