postgres 9.3+:约束以确保数据库中存在表和列

时间:2017-02-10 19:11:11

标签: database postgresql constraints

如何确保新记录包含引用数据库中当前存在的架构,表和列的值?

例如,给出一个表:

CREATE TEMP TABLE "column_reference" (
      "gid"    SERIAL PRIMARY KEY
    , "val"    INTEGER
    , "schema" TEXT
    , "table"  TEXT
    , "column" TEXT
);

如何确保schema.table.column存在?

我尝试了一个fkey到information_schema.columns,但是,当然,不允许使用外键访问。

columns视图定义中我还需要几个表来获取模式,表和列名,这样我就无法创建源表的单个外键。 / p>

我目前的解决方法是从__columns视图手动创建information_schema.columns表,然后引用它。考虑到我此时正好在这个项目上进行控制,但是我正在寻找一个永久的,动态的解决方案。

我可以使用不同的约束或方法吗?

1 个答案:

答案 0 :(得分:2)

您可以创建一个trigger function来检查您想要的内容,并将此函数与在INSERT或表的UPDATE之前触发的触发器相关联:

这可能是你的触发功能:

CREATE FUNCTION column_reference_check()
    RETURNS trigger
    LANGUAGE 'plpgsql'
AS 
$BODY$
begin
    /* Check for the existence of the required column */
    if EXISTS (
          SELECT * 
          FROM information_schema.columns 
          WHERE
                  table_schema = new.schema
              AND table_name   = new.table
              AND column_name  = new.column )
    then
        /* Everything Ok */
        return new ;
    else
        /* This is approx. what would happen if you had a constraint */
        RAISE EXCEPTION 'Trying to insert non-matching (%, %, %)', new.schema, new.table, new.column ;

        /* As an alternative, you could also just return NULL
           As a result, the row is *not* inserted, but execution continues */
        return NULL ;
    end if ;
 end ;
$BODY$;

要将此功能与触发器相关联,您可以使用:

CREATE TRIGGER column_reference_check_trg
    BEFORE INSERT OR UPDATE OF "schema", "table", "column"
    ON column_reference
    FOR EACH ROW
    EXECUTE PROCEDURE column_reference_check();

现在您可以尝试执行以下INSERT,这应该会成功:

INSERT INTO column_reference 
   VALUES (2, 1, 'pg_catalog', 'pg_statistic', 'starelid');

但如果你试试这个:

INSERT INTO column_reference 
   VALUES (-1, 1, 'false_schema', 'false_table', 'false_column');

...你得到一个例外:

ERROR:  Trying to insert non-matching (false_schema, false_table, false_column)
CONTEXT:  PL/pgSQL function column_reference_check() line 16 at RAISE