SQL 约束和 ON DELETE

标签 sql postgresql

举一个外键约束的简单例子:

CREATE TABLE products (
  product_no integer PRIMARY KEY,
  name text,
  price numeric
);

CREATE TABLE orders (
  order_id integer PRIMARY KEY,
  shipping_address text,
  ...
);

CREATE TABLE order_items (
  product_no integer REFERENCES products ON DELETE CASCADE,
  order_id integer REFERENCES orders ON DELETE CASCADE,
  quantity integer,
  PRIMARY KEY (product_no, order_id)
);

当从产品或订单中删除一行时,引用 order_items 中的行也将被删除。

但是 - 可以让数据库检测产品或订单中的孤立行(没有引用 order_item 的行)并删除它们吗?我知道我可以设置一个查询来轻松完成它,但在更大更复杂的模式中,这可能是很多查询。不知道有没有类似ON DELETE CASCADE的机制?

最佳答案

这是一个没有引用计数的例子:

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE one
    ( id SERIAL NOT NULL PRIMARY KEY
    , name VARCHAR
    );
CREATE TABLE two
    ( id SERIAL NOT NULL PRIMARY KEY
    , name VARCHAR
    );
CREATE TABLE onetwo
    ( one_id INTEGER REFERENCES one(id)
    , two_id INTEGER REFERENCES two(id)
        , PRIMARY KEY(one_id, two_id)
    );
CREATE INDEX onetwo_rev ON onetwo (two_id,one_id);

  -- Populate the tables.
INSERT INTO one(name) select 'One_name_' || gs::text FROM generate_series(1,5) gs ;
INSERT INTO two(name) select 'Two_name_' || gs::text FROM generate_series(1,5) gs ;
INSERT INTO onetwo (one_id, two_id)
SELECT o.id, t.id
FROM one o
JOIN two t ON 1=1
        ;
  -- Remove some random associations between one&two,
  -- and remove any unreferenced records from one and two
DELETE FROM onetwo WHERE random() < 0.7;
DELETE FROM one dd WHERE NOT EXISTS(SELECT * FROM onetwo ot WHERE ot.one_id=dd.id) ;
DELETE FROM two dd WHERE NOT EXISTS(SELECT * FROM onetwo ot WHERE ot.two_id=dd.id) ;

SELECT * FROM onetwo;
SELECT * FROM one;
SELECT * FROM two;

CREATE OR REPLACE FUNCTION check_the_deletes() RETURNS TRIGGER AS $meat$
BEGIN
    DELETE FROM one dd
    WHERE dd.id=OLD.one_id
    AND NOT EXISTS(SELECT * FROM onetwo ot WHERE ot.one_id=dd.id)
       ;
    DELETE FROM two dd
    WHERE dd.id=OLD.two_id
    AND NOT EXISTS(SELECT * FROM onetwo ot WHERE ot.two_id=dd.id)
       ;
    RETURN NEW;
END; $meat$
LANGUAGE plpgsql;

CREATE TRIGGER update_last_sale
    AFTER DELETE ON onetwo
    FOR EACH ROW
    EXECUTE PROCEDURE check_the_deletes()
     ;

SELECT o.name AS name1
        , t.name AS name2
FROM onetwo ot
JOIN one o ON o.id = ot.one_id
JOIN two t ON t.id = ot.two_id
        ;

  -- Delete some random associations
  -- the trigger should also remove any unreferenced rows
  -- from one and two tables.
DELETE FROM onetwo WHERE random() < 0.4;

SELECT o.name AS name1
        , t.name AS name2
FROM onetwo ot
JOIN one o ON o.id = ot.one_id
JOIN two t ON t.id = ot.two_id
        ;
SELECT * FROM one;
SELECT * FROM two;

关于SQL 约束和 ON DELETE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15087590/

相关文章:

sql - 如何在窗口函数中使用环形数据结构

SQL Server 存储过程从数据库备份文件恢复

ruby-on-rails - Rails 中的 Postgresql 不同,在 created_at 上排序

javascript - 在避免重复的同时有效地在 postgres 中实现分页?

mysql - Heroku 的 Rails 数据库特定查询

postgresql - 使用函数更新 PostgreSQL 表中的数组

mysql - 组函数与 AVG 函数的使用无效

mysql - 在多个 NOT IN 上优化 MySQL 查询

c# - Entity Framework 查询思路(group by)

python - 更改 Django 外键中的 UUID 格式