Phi*_*shy 8 postgresql database-design view plpgsql
我有一张名为赋值的表.我希望能够使用assignments.column或homework.column读取/写入此表中的所有列,我该怎么做?
我知道这不是你通常会做的事情.我需要能够在短时间内提供向后兼容性.
我们有一个iOS应用程序,目前直接对数据库进行postgresql查询.我们正在更新所有应用以使用API.在构建API的过程中,开发人员决定更改表的名称,因为我们(愚蠢地)认为我们不需要向后兼容性.
现在,V1.0和API都需要能够写入这个表,所以我以后不必再做一些伏都教来转移/合并数据......我们正在使用Ruby on Rails作为API.
在 Postgres 9.3 或更高版本中,简单VIEW是自动“可更新”的。手册:
简单视图是可自动更新的:系统将允许 在视图上使用
INSERT、UPDATE和DELETE语句,就像在常规表上一样。如果视图满足以下所有条件,则它可以自动更新:
该视图的
FROM列表中必须只有一个条目,该条目必须是表或另一个可更新的视图。视图定义的顶层不得包含
WITH、DISTINCT、GROUP BY、HAVING、LIMIT或子句。OFFSET视图定义不得在顶层包含集合操作(
UNION 、INTERSECT或)。EXCEPT视图的选择列表不得包含任何聚合、窗口函数或集合返回函数。
如果不满足这些条件之一(或者对于现在已经过时的 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$;
Run Code Online (Sandbox Code Playgroud)
CREATE TRIGGER insupbef
INSTEAD OF INSERT OR UPDATE OR DELETE ON assignments_published
FOR EACH ROW EXECUTE PROCEDURE trg_ia_insupdel();
Run Code Online (Sandbox Code Playgroud)
assignments_published必须是 a VIEW,INSTEAD OF触发器仅允许用于视图。
动态 SQL(在参考资料UPDATE部分中)并不是绝对必要的,只是为了自动覆盖将来对表布局的更改。表和PK的名称仍然是硬编码的。
没有子块更简单,可能更便宜(就像你一样)。
使用(SELECT ($1).*)而不是较短的VALUES ($1.*)来保留列名称。
我的命名约定:我在前面添加trg_触发器函数,后跟表示目标表的缩写,最后分别添加一个或多个标记ins、up和delfor INSERT,UPDATE以及DELETE。触发器的名称是函数名称的副本,去掉了前两部分。这纯粹是一个惯例和品味的问题,但事实证明对我来说很有用,因为名称说明了目的并且仍然很短。
已经提到的相关答案中有更多解释:
到目前为止,这就是我使用触发功能的地方,任何反馈将不胜感激。它是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
classrooms
Run Code Online (Sandbox Code Playgroud)
查看:tasks_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$;
Run Code Online (Sandbox Code Playgroud)
扳机
CREATE TRIGGER assignments_published_trigger
INSTEAD OF INSERT OR UPDATE OR DELETE ON
assignments_published FOR EACH ROW EXECUTE PROCEDURE assignments_published_trigger_func();
Run Code Online (Sandbox Code Playgroud)
表:iAssignments_classes
列:
class_assignment_id
guid
assignment_published_id
Run Code Online (Sandbox Code Playgroud)
查看:tasks_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();
Run Code Online (Sandbox Code Playgroud)