Abe*_*ker 5 postgresql join view update
我有两张桌子,products并且subscriptions:
CREATE TABLE products (
id bigint NOT NULL,
title character varying(75),
description text,
manufacturer_id bigint,
created_at timestamp without time zone,
updated_at timestamp without time zone,
mpn text,
visible boolean DEFAULT false NOT NULL
);
CREATE TABLE subscriptions (
id bigint NOT NULL,
product_id bigint NOT NULL,
user_id bigint NOT NULL,
created_at timestamp without time zone,
updated_at timestamp without time zone
);
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,我通常需要知道某个产品的订阅者数量,而在应用程序中所有正确位置使用此逻辑是很棘手的。所以我想products用已经包含该信息的视图替换该表。所以我这样做了:
ALTER TABLE ONLY products
RENAME TO products_raw;
CREATE VIEW products AS
SELECT products_raw.*, COALESCE(a.subscriptions_count, 0) AS subscriptions_count
FROM products_raw
LEFT OUTER JOIN (
SELECT b.product_id, COUNT(*) subscriptions_count
FROM subscriptions b
GROUP BY b.product_id
) a ON a.product_id = products_raw.id;
Run Code Online (Sandbox Code Playgroud)
但是,products由于JOIN- 我希望在products_raw表上执行任何 INSERT/UPDATE/DELETE 操作,而subscriptions_count在适用时忽略虚拟,因此该视图不可自动更新。
这是我第一次创建视图或规则,但我尝试了以下规则:
CREATE RULE products_insert_rule AS ON INSERT TO products DO INSTEAD
INSERT INTO products_raw VALUES(NEW.*);
Run Code Online (Sandbox Code Playgroud)
但是 Postgres 不喜欢这样:
PG::SyntaxError: ERROR: INSERT has more expressions than target columns
LINE 13: INSERT INTO products_raw VALUES(NEW.*);
^
Run Code Online (Sandbox Code Playgroud)
我也尝试写一个INSTEAD OF INSERT触发器:
CREATE FUNCTION products_insert() RETURNS trigger AS $$
BEGIN
INSERT INTO products_raw VALUES (NEW.*);
RETURN NEW;
END; $$ LANGUAGE PLPGSQL;
CREATE TRIGGER products_insert INSTEAD OF INSERT ON products
FOR EACH ROW EXECUTE PROCEDURE products_insert();
Run Code Online (Sandbox Code Playgroud)
但得到了基本相同的错误消息:
PG::SyntaxError: ERROR: INSERT has more expressions than target columns
LINE 1: INSERT INTO products_raw VALUES (NEW.*)
^
QUERY: INSERT INTO products_raw VALUES (NEW.*)
CONTEXT: PL/pgSQL function products_insert() line 3 at SQL statement
: INSERT INTO "products" ("title", "description", "created_at", "updated_at") VALUES ($1, $2, $3, $4)
Run Code Online (Sandbox Code Playgroud)
我正在使用 Postgres 9.4。任何提示将不胜感激。
编辑:我更接近这个触发器,但由于我不确定如何将products_rawrowtype 转换为products. 我也不喜欢必须重复默认值(包括id序列)的方向......
CREATE FUNCTION products_insert() RETURNS trigger AS $$
DECLARE
p products_raw%ROWTYPE;
BEGIN
IF p.id IS NULL THEN
p.id = NEXTVAL('products_id_seq');
END IF;
IF p.visible IS NULL THEN
p.visible = false;
END IF;
INSERT INTO products_raw VALUES(p.*);
RETURN p;
END; $$ LANGUAGE PLPGSQL;
CREATE TRIGGER products_insert INSTEAD OF INSERT ON products
FOR EACH ROW EXECUTE PROCEDURE products_insert();
Run Code Online (Sandbox Code Playgroud)
我用上面的触发器得到的错误是
PG::DatatypeMismatch: ERROR: returned row structure does not match the structure of the triggering table
DETAIL: Number of returned columns (8) does not match expected column count (9).
CONTEXT: PL/pgSQL function products_insert() during function exit
: INSERT INTO "products" ("title", "description", "created_at", "updated_at") VALUES ($1, $2, $3, $4)
Run Code Online (Sandbox Code Playgroud)
小智 5
您不能使用 NEW.*,因为视图包含基础表中不存在的列。您必须明确列出要添加的列。正如上面人们所解释的,这不起作用的原因是您没有提供默认值。您可能需要考虑使用 COALESCE() 来实现此目的。
| 归档时间: |
|
| 查看次数: |
3121 次 |
| 最近记录: |