为 PostgreSQL 表创建别名

Posted

技术标签:

【中文标题】为 PostgreSQL 表创建别名【英文标题】:Create Alias for PostgreSQL Table 【发布时间】:2014-06-11 13:47:03 【问题描述】:

我有一个名为 assignments 的表。我希望能够使用 assignments.column 或 homework.column 读取/写入此表中的所有列,我该怎么做?

我知道这不是你通常会做的事情。我需要能够做到这一点,以便在短时间内提供向后兼容性。

我们有一个 ios 应用程序,目前对数据库执行直接 postgresql 查询。我们正在更新我们所有的应用程序以使用 API。在构建 API 的过程中,开发人员决定更改表的名称,因为我们(愚蠢地)认为我们不需要向后兼容。

现在,V1.0 和 API 都需要能够写入这个表,所以我以后不必做一些巫术来传输/合并数据...... 我们将 Ruby on Rails 用于 API。

【问题讨论】:

Postgres 没有同义词,例如 Oracle 有。你能确切地说明你的用途是什么吗?也许视图可以解决问题。 在编辑中添加了详细信息。 @Mureinik:视图是要走的路。你应该这样回答。 你能在视图上插入/更新/删除吗? @PhillipBoushy:是的 - 有规则或触发器。 Here is a recent related question (and answer) on dba.SE demonstrating INSTEAD triggers.。 Another more answer with more explanation. 【参考方案1】:

对于 Postgres 9.3,以下内容就足够了:

CREATE VIEW homework AS SELECT * FROM assignments;

之所以有效,是因为简单的视图可以自动更新 (see docs)。

【讨论】:

不幸的是,我需要兼容 PostgreSQL 9.1.9 和 9.2.4(OS X 10.8 和 9 中的内置 PostgreSQL。 在这种情况下,您注定要使用触发器或规则,但是升级可能比实施这些更容易。 我很想升级到 9.3,但这是所有 OS X 服务都使用的内置 PostgreSQL 数据库......所以,这可能有点危险。【参考方案2】:

在 Postgres 9.3 或更高版本中,简单的 VIEW 是自动“可更新”的。 The manual:

简单视图可自动更新:系统将允许 INSERTUPDATEDELETE 语句将在视图中使用 与在普通桌子上的方式相同。视图可自动更新 如果满足以下所有条件:

视图在其FROM 列表中必须有一个条目,该条目必须是表或另一个可更新视图。

视图定义不得在顶层包含WITHDISTINCTGROUP BYHAVINGLIMITOFFSET 子句。

视图定义不得在顶层包含集合操作(​​UNIONINTERSECTEXCEPT)。

视图的选择列表不得包含任何聚合、窗口函数或集合返回函数。

如果不满足这些条件之一(或者对于现在已经过时的 Postgres 9.2 或更早版本),手动设置可能会完成这项工作。

以您正在进行的工作为基础:

触发功能

CREATE OR REPLACE FUNCTION trg_ia_insupdel()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
DECLARE
   _tbl  CONSTANT regclass := 'iassignments_assignments';
   _cols text;
   _vals text;
BEGIN
   CASE TG_OP
   WHEN 'INSERT' THEN
      INSERT INTO iassignments_assignments
      VALUES (NEW.*);

      RETURN NEW;

   WHEN 'UPDATE' THEN
      SELECT INTO _cols, _vals
             string_agg(quote_ident(attname), ', ')   -- incl. pk col!
           , string_agg('n.' || quote_ident(attname), ', ')
      FROM   pg_attribute
      WHERE  attrelid = _tbl        -- _tbl converted to oid automatically
      AND    attnum > 0             -- no system columns
      AND    NOT attisdropped;      -- no dropped (dead) columns

      EXECUTE format('
         UPDATE %s t
         SET   (%s) = (%s)
         FROM  (SELECT ($1).*) n
         WHERE    t.published_assignment_id
             = ($2).published_assignment_id' -- match to OLD value of pk
       , _tbl, _cols, _vals)        -- _tbl converted to text automatically
      USING NEW, OLD;

      RETURN NEW;

   WHEN 'DELETE' THEN
      DELETE FROM iassignments_assignments
      WHERE  published_assignment_id = OLD.published_assignment_id;

      RETURN OLD;
   END CASE;

   RETURN NULL;  -- control should never reach this
END
$func$;

触发器

CREATE TRIGGER insupbef
INSTEAD OF INSERT OR UPDATE OR DELETE ON assignments_published
FOR EACH ROW EXECUTE PROCEDURE trg_ia_insupdel();

注意事项

assignments_published 必须是 VIEWINSTEAD OF 触发器只允许用于视图。

动态 SQL(在UPDATE 部分中)并不是绝对必要的,只是为了自动涵盖对表布局的未来更改。 table 和 PK 的名称仍然是硬编码的。

没有sub-block(就像你曾经拥有的那样)更简单,可能更便宜。

使用(SELECT ($1).*) 而不是较短的VALUES ($1.*) 来保留列名。

我的命名约定:我在 触发函数 前面加上 trg_,然后是表示目标表的缩写,最后是 insup 和 @987654350 中的一个或多个标记@ 分别代表 INSERTUPDATEDELETE。触发器的名称是函数名称的副本,去掉了前两部分。这纯粹是惯例和品味的问题,但事实证明对我很有用,因为名称说明了目的并且仍然很短。

已经提到的相关答案中的更多解释:

Update multiple columns in a trigger function in plpgsql

【讨论】:

函数/触发器名称是否有方法?它们对我来说似乎相当神秘。我将在我的测试数据库上对此进行测试,看看它是如何工作的。 @PhillipBoushy:嗯,对,我为此添加了一些解释。 我相信这确实回答了它,不幸的是,我没有机会完全测试它。这周我会尝试这样做,并将您的答案标记为正确。 @ErwinBrandstetter。我试图复制你的结果。但。我相信你现在应该INSERT INTO iassignments_assignments VALUES (NEW.*);。另一点是,当我尝试将assignments_published 设为表时,触发器会出错。 ERROR: "assignments_published" is a table DETAIL: Tables cannot have INSTEAD OF triggers. 虽然我还没有理解函数的意图.... @Mark:是的,VALUES (NEW.*)INSTEAD OF 触发器只允许用于视图,不能用于表。无论如何,这个答案是旧的。如果可能,只需使用自动更新的视图(自 Postgres 9.3 起)。我只使 UPDATE 部分动态化,因为 OP 在他的回答中提出了它。【参考方案3】:

到目前为止,这是我使用触发功能的地方,任何反馈都将不胜感激。它是http://vibhorkumar.wordpress.com/2011/10/28/instead-of-trigger/ 和Update multiple columns in a trigger function in plpgsql 的组合

表:iassignments_assignments

列:

published_assignment_id
name
filepath
filename
link
teacher
due date
description
published
clas-s-rooms

查看:assignments_published - SELECT * FROM iassignments_assignments

assignments_published 的触发函数

CREATE OR REPLACE FUNCTION assignments_published_trigger_func()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $function$
   BEGIN
      IF TG_OP = 'INSERT' THEN
        EXECUTE format('INSERT INTO %s SELECT ($1).*', 'iassignments_assignments')
        USING NEW;
        RETURN NEW;
      ELSIF TG_OP = 'UPDATE' THEN
        DECLARE
          tbl = 'iassignments_assignments';
          cols text;
          vals text;
        BEGIN
          SELECT INTO cols, vals
           string_agg(quote_ident(attname), ', ')
           ,string_agg('x.' || quote_ident(attname), ', ')
          FROM   pg_attribute
          WHERE  attrelid = tbl
          AND    NOT attisdropped   -- no dropped (dead) columns
          AND    attnum > 0;        -- no system columns

          EXECUTE format('
          UPDATE %s t
          SET   (%s) = (%s)
          FROM  (SELECT ($1).*) x
          WHERE  t.published_assignment_id = ($2).published_assignment_id'
          , tbl, cols, vals)
          USING NEW, OLD;

          RETURN NEW;
        END
      ELSIF TG_OP = 'DELETE' THEN
       DELETE FROM iassignments_assignments WHERE published_assignment_id=OLD.published_assignment_id;
       RETURN NULL;
      END IF;
      RETURN NEW;
    END;
$function$;

触发器

CREATE TRIGGER assignments_published_trigger
INSTEAD OF INSERT OR UPDATE OR DELETE ON
assignments_published FOR EACH ROW EXECUTE PROCEDURE assignments_published_trigger_func();

表:iassignments_classes

列:

class_assignment_id
guid
assignment_published_id

查看:assignments_class - SELECT * FROM assignments_classes

assignments_class 的触发函数

**一旦我收到关于另一个函数的反馈并知道它已创建,我将创建此函数,因此我(希望)对这个函数只需要很少的更改。

触发器

CREATE TRIGGER assignments_class_trigger
INSTEAD OF INSERT OR UPDATE OR DELETE ON
assignments_class FOR EACH ROW EXECUTE PROCEDURE assignments_class_trigger_func();

【讨论】:

为什么是动态报表?您想涵盖未来对表格的更改吗? (更简单和更快的)静态版本是否足够好?如果您稍后应该更改表格,您将更改触发器... 我无法控制需要对其进行的查询或数据库结构,我只是想提出一个解决方案来使其向后兼容,因此,我怀疑它需要是动态的。只要将来易于更新,我就可以让它更加静态。

以上是关于为 PostgreSQL 表创建别名的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 别名

PostgreSQL 别名

10.PostgreSQL别名

使用 PostgreSQL 创建数据透视表

Ubuntu PostgreSQL安装和配置

postgresql命令操作