根据另一个表中的值删除行

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如果可以的话。它效率低下并且可能很危险。相关:

Select rows which are not present in other table

②“订单”是SQL中的reserved word。最好选择合法的标识符,否则您必须始终使用双引号。

③我用RETURNS int表示该行是否真的被删除了。如果DELETE 未通过,该函数将返回 NULL。可选添加。


对于触发器实现,请考虑以下密切相关的答案:

Foreign key contraints in many-to-many relationships

【讨论】:

以上是关于根据另一个表中的值删除行的主要内容,如果未能解决你的问题,请参考以下文章

根据另一个工作表中的可见范围删除行

Google Script:如果行中的值存在于另一个工作表中,则删除行

根据另一个表中的值插入和/或更新记录

如何根据一个表中的特定值从3个表中删除行[重复]

根据另一个表中的值更新表中的值[重复]

根据一列删除重复项并根据另一表中的数据进行过滤