删除级联时是否有“反向”选项?

问题描述 投票:0回答:4

假设我在 SQL Server 中有以下数据库:

CREATE TABLE [Order]
(
  ID BIGINT IDENTITY(1,1)
  CONSTRAINT PK_Order PRIMARY KEY CLUSTERED (ID)
);

CREATE TABLE OrderItem
(
  ID BIGINT IDENTITY(1,1),
  ORDER_ID BIGINT NOT NULL,
  PRICE_ID BIGINT NOT NULL,
  DISCOUNTED_PRICE_ID BIGINT NULL,
  CONSTRAINT PK_OrderItem PRIMARY KEY CLUSTERED (ID)
);

CREATE TABLE Price
(
  ID BIGINT IDENTITY(1,1),
  AMOUNT FLOAT NOT NULL,
  CURRENCY VARCHAR(3) NOT NULL,
  CONSTRAINT PK_Price PRIMARY KEY CLUSTERED (ID)
);

ALTER TABLE OrderItem ADD CONSTRAINT FK_OrderItem_Order
FOREIGN KEY (ORDER_ID) REFERENCES [Order](ID) ON DELETE CASCADE;

ALTER TABLE OrderItem ADD CONSTRAINT FK_OrderItem_Price
FOREIGN KEY (PRICE_ID) REFERENCES Price(ID);

ALTER TABLE OrderItem ADD CONSTRAINT FK_OrderItem_DiscountedPrice
FOREIGN KEY (DISCOUNTED_PRICE_ID) REFERENCES Price(ID);

如果我删除订单,所有订单商品都将被删除(因为

ON DELETE CASCADE
上的
FK_OrderItem_Order
约束),但相应的价格(正常价格和折扣价格)将永远保留在数据库中。

SQL Server(或通用 SQL)中是否有任何选项可以从

Price
表中删除相应的价格?

我可以想到一个完美匹配的触发器,但对于这样简单(且常见)的任务来说太麻烦了。我更愿意在我的约束(

FK_OrderItem_Price
FK_OrderItem_DiscountedPrice
)上指定一些内容,基本上说“这是一对一的关系”,如果子项是,则删除父项(在本例中,
Price
是父表)已删除。

sql sql-server database database-design
4个回答
16
投票

简而言之:不。级联仅适用于从父级到子级1,反之则不然。

有人认为,当一些父母失去最后一个孩子时,他们应该被移除,但这根本不是当前 DBMS 的实现方式。

您必须使用触发器来执行此类“特殊”参考操作,或者使用批处理作业(它不必立即发生)。或者将操作隐藏在某种明确执行此操作的 API(存储过程、中间层方法)背后。

另请参阅:订单稳定性


1 在您的情况下,Order 和 Price 都充当 OrderItem 的父级。


5
投票

OrderItemID
添加到
Price
,并建立级联删除关系。这一列当然是多余的,但它允许您在正确的方向上进行级联删除。

考虑将

Price
表两次内联到
OrderItems
中。由于这是 1:1 的关系,因此您可以这样做。无论您是否喜欢这个解决方案,这都是一个品味问题。


5
投票

您可以创建一个充当反向级联的触发器:

DELIMITER $$
CREATE TRIGGER reverse_cascade_OrderItem_Price
AFTER DELETE ON `OrderItem`
FOR EACH ROW
BEGIN
    DELETE FROM `Price` WHERE ID = old.PRICE_ID;
END$$

0
投票

对于那些仍然对答案不满意的人,删除行后,您可以在价格表上触发第二个查询,以使用带有左连接的删除来删除链接表中没有相应链接的所有行。

© www.soinside.com 2019 - 2024. All rights reserved.