根据另一个表中的值删除行
Posted
技术标签:
【中文标题】根据另一个表中的值删除行【英文标题】:Delete rows depending on values from another table 【发布时间】:2020-05-26 15:50:00 【问题描述】:如何根据另一个表中的值从我的customer
表中删除行,比如说orders
?
如果客户没有活动订单,他们应该能够连同他们的行一起从数据库中删除(使用CASCADE
完成)。但是,如果他们有任何活动订单,则无法删除。
我想到了一个 PLPGSQL 函数,然后在触发器中使用它来检查,但我迷路了。我有一个基本的 SQL 块,下面显示了我相应地删除记录的第一个想法。但是它不能正常工作,因为它会删除客户而不考虑状态,它只需要在此功能中取消一个订单,而不是全部取消。
CREATE OR REPLACE FUNCTION DelCust(int)
RETURNS void AS $body$
DELETE FROM Customer
WHERE CustID IN (
SELECT CustID
FROM Order
WHERE Status = 'C'
AND CustID = $1
);
$body$
LANGUAGE SQL;
SELECT * FROM Customer;
我还尝试使用 PLPGSQL 函数返回触发器,然后使用触发器来帮助删除和检查,但我迷路了。关于如何解决这个问题的任何想法?有什么好的资源可供进一步阅读?
【问题讨论】:
请解释WHERE Status = 'C'
的确切作用。您的 Postgres 版本和基本表定义(CREATE TABLE
语句)也会有所帮助。
【参考方案1】:
你们很亲密。我建议你使用NOT IN
而不是IN
:
DELETE FROM Customer
WHERE CustID = $1 AND
CustID NOT IN (SELECT DISTINCT CustID
FROM Order
WHERE Status = 'A');
我在这里猜测Status = 'A'
的意思是“活动订单”。如果是其他东西,请适当更改代码。
【讨论】:
【参考方案2】:您的基本功能可以这样工作:
CREATE OR REPLACE FUNCTION del_cust(_custid int)
RETURNS int --③
LANGUAGE sql AS
$func$
DELETE FROM customer c
WHERE c.custid = $1
AND NOT EXISTS ( -- ①
SELECT FROM "order" o -- ②
WHERE o.status = 'C' -- meaning "active"?
AND o.custid = $1
);
RETURNING c.custid; -- ③
$func$;
①Avoid NOT IN
如果可以的话。它效率低下并且可能很危险。相关:
②“订单”是SQL中的reserved word。最好选择合法的标识符,否则您必须始终使用双引号。
③我用RETURNS int
表示该行是否真的被删除了。如果DELETE
未通过,该函数将返回 NULL。可选添加。
对于触发器实现,请考虑以下密切相关的答案:
Foreign key contraints in many-to-many relationships【讨论】:
以上是关于根据另一个表中的值删除行的主要内容,如果未能解决你的问题,请参考以下文章