删除前删除相关记录触发postgresql
Posted
技术标签:
【中文标题】删除前删除相关记录触发postgresql【英文标题】:Delete related records before delete trigger postgresql 【发布时间】:2016-11-24 03:00:00 【问题描述】:我需要做一个触发器,它将删除相关表中的相关行。是的,我知道 ON DELETE CASCADE,但问题是我需要使用触发器来完成。我用谷歌搜索了几个小时,但没有找到 Postgesql 的解决方案。我使用 postgresql 9.4,pgAdmin III。
我有以下表格:
CREATE TABLE "Customer"
(
"Id" serial NOT NULL,
"ContactPerson" text NOT NULL,
"Address" text NOT NULL,
"PhoneNumber" "PhoneNumber" NOT NULL,
CONSTRAINT "CustomerId (PK)" PRIMARY KEY ("Id")
)
WITH (
OIDS=FALSE
);
CREATE TABLE "Order"
(
"Id" serial NOT NULL,
"OrderDate" date NOT NULL DEFAULT ('now'::text)::date,
"Amount" integer NOT NULL DEFAULT 1,
"CustomerId" integer NOT NULL,
"GoodId" integer NOT NULL,
CONSTRAINT "OrderId (PK)" PRIMARY KEY ("Id"),
CONSTRAINT "CustomerId (FK)" FOREIGN KEY ("CustomerId")
REFERENCES "Customer" ("Id") MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT "GoodId (FK)" FOREIGN KEY ("GoodId")
REFERENCES "Good" ("Id") MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT "AmountCheck" CHECK ("Amount" > 0),
CONSTRAINT "OrderDateCheck" CHECK ("OrderDate" <= 'now'::text::date)
)
WITH (
OIDS=FALSE
);
我使用此查询创建触发器:
CREATE FUNCTION DeleteCustomerWithOrders() RETURNS trigger AS $DeleteCustomerWithOrders$
BEGIN
DELETE FROM "Order"
WHERE "Order"."CustomerId" = (SELECT "Id" FROM "Customer");
RETURN "Customer";
END;
$DeleteCustomerWithOrders$ LANGUAGE plpgsql;
CREATE TRIGGER DeleteCustomerWithOrders BEFORE DELETE ON "Customer"
EXECUTE PROCEDURE DeleteCustomerWithOrders();
查询运行良好,但我尝试从Customer
中删除行,但出现错误:
(“客户”列不存在)
文档中只有 ON INSERT 或 UPDATE 触发器的示例,它们使用RETURN NEW
。我还看到在 sql-server 中使用 OLD
。对我来说没有任何帮助。 WHERE
也可能有错误。
更新
感谢帕特里克。这解决了第一个问题,但会导致另一个问题。
错误:记录 old
未赋值。详细信息:对于未分配的记录,未定义相关结构。
【问题讨论】:
无关,但是:你真的应该避免那些可怕的带引号的标识符。从长远来看,他们更麻烦,然后他们是值得的。如果你用英文发布错误信息也更好(设置lc_messages=English
)
lc_messages=English
我应该在脚本或 pgAdmin 设置中编写它?对不起,不明白,你是什么意思“可怕的引用标识符”,我的函数名?
【参考方案1】:
您的代码有两个小问题。
触发器在表"Customer"
上运行,但在触发器函数中,您使用预定义的参数OLD
引用该表的行被删除。另外,不要从该行中选择id
,而只是引用它(子查询实际上是从表中检索所有id
s,这也是错误的)。
触发函数应该是这样的:
CREATE FUNCTION DeleteCustomerWithOrders() RETURNS trigger AS
$DeleteCustomerWithOrders$
BEGIN
DELETE FROM "Order"
WHERE "Order"."CustomerId" = OLD."Id";
RETURN OLD;
END;
$DeleteCustomerWithOrders$ LANGUAGE plpgsql;
您收到的错误来自语句RETURN "Customer";
。 RETURN 语句需要一个trigger
参数,但找到一个标识符。然后系统将此解释为 SELECT 语句,该语句将返回 trigger
对象,但该语句显然不完整:"Customer"
在选择列表中,因此被解释为列名,但没有行源 (FROM ...
) 来完成语句,因此无法解析列名。
【讨论】:
不幸的是,这解决了屏幕截图上的问题,导致另一个问题。请在第一次按摩时查看更新。 触发功能没有问题,据我所知。您是否可能直接调用此函数(例如,不是在 DELETE 时自动调用,而是手动调用)? 不,我使用表数据视图或DELETE FROM
删除它。在这两种情况下我都得到了这个错误。以上是关于删除前删除相关记录触发postgresql的主要内容,如果未能解决你的问题,请参考以下文章