自动删除没有外部引用的行

问题描述

我正在使用sqlite3。 我有一个“货币”表,还有两个表使用外键引用货币表,如下所示:

CREATE TABLE currencies (
     currency        TEXT NOT NULL PRIMARY KEY
    );

CREATE TABLE table1 (
     currency        TEXT NOT NULL PRIMARY KEY,FOREIGN KEY(currency) 
        REFERENCES currencies(currency)
    );

CREATE TABLE table2 (
     currency        TEXT NOT NULL PRIMARY KEY,FOREIGN KEY(currency) 
        REFERENCES currencies(currency)
    );

我想确保“ currency”表中未被“ table1”和“ table2”的任何行引用的行将被自动删除。它的行为应类似于某种ref-counted对象。当参考计数达到零时,应删除“货币”表中的相关行。

什么是解决此问题的“ SQL方式”?

我愿意重新设计我的桌子,如果它可以导致一个优雅的解决方案。 我宁愿避免需要在应用程序方面进行额外工作的解决方案,或者需要定期清理的解决方案。

解决方法

没有自动执行此操作的方法。相反,可以使用级联删除外键引用进行处理。相反的是,删除货币后,所有相关行都被删除。

您可以安排每天执行的工作,例如:

delete from currencies c
    where not exists (select 1 from table1 t1 where t1.currency = c.currency) and
          not exists (select 1 from table2 t2 where t2.currency = c.currency);
      
,

如果您需要自动执行此操作的方法,那么大多数dbms都会提供触发机制。您可以在运行以下查询的更新和删除操作上创建触发器:

您可以为此使用左联接:

https://www.w3schools.com/sql/sql_join_left.asp

即使左侧表中没有对应的行,它也会为左侧表中的所有行返回一行,将右侧的行替换为null。然后,您可以检查一个不为null的右表字段,其中null为null。这将过滤右表中没有对应行的行。

例如:

SELECT currencies.currency FROM currencies LEFT JOIN table1 WHERE table1.currency IS NULL

将显示表1的相关行。 您可以对表二做同样的事情。

这将给您两个查询,显示哪些行没有couterpart。 然后,您可以在结果上使用相交,以使行中的任何一行都没有couterpart:

SELECT * FROM query1 INTERSECT SELECT * FROM query2

现在,您有了要删除的货币列表。

您可以通过使用子查询删除来完成此操作:

DELETE FROM currencies WHERE currency IN (SELECT ...)
,

分别在AFTER DELETE TRIGGERtable1中创建一个table2

CREATE TRIGGER remove_currencies_1 AFTER DELETE ON table1
BEGIN
  DELETE FROM currencies
  WHERE currency = OLD.currency
    AND NOT EXISTS (SELECT 1 FROM table2 WHERE currency = OLD.currency);
END;

CREATE TRIGGER remove_currencies_2 AFTER DELETE ON table2
BEGIN
  DELETE FROM currencies
  WHERE currency = OLD.currency
    AND NOT EXISTS (SELECT 1 FROM table1 WHERE currency = OLD.currency);
END;

每次您删除table1table2中的行时,所涉及的触发器都会检查另一个表是否包含已删除的currency,如果不包含该行,将从currencies中删除。

请参见demo

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...