假设我在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
是这里的父表如果孩子被删除了。
答案 0 :(得分:8)
简而言之:不。级联只能从父母到孩子 1 ,而不是相反。
可以说有些父母在失去最后一个孩子时应该被移除,但这并不是当前DBMS的实施方式。您必须使用触发器 2 进行此类“特殊”参照操作。
话虽这么说,这个模型有点奇怪。价格不应与产品 3 相关联吗?
1 在您的情况下,Order和Price都充当OrderItem的父母。
2 或批处理作业,它不必立即发生。或隐藏某种明确执行此操作的API(存储过程,中间层方法)背后的操作。
3 尽管有order stability的担忧。
答案 1 :(得分:3)
将OrderItemID
添加到Price
并设置级联删除关系。该列当然是多余的,但它允许您在正确的方向上进行级联删除。
考虑将Price
表格两次内联到OrderItems
。由于这是1:1的关系,你可以做到这一点。无论您是否喜欢这种解决方案,都是一种品味问题。
答案 2 :(得分:0)
您可以创建一个充当反向级联的触发器:
DELIMITER $$
CREATE TRIGGER reverse_cascade_OrderItem_Price
AFTER DELETE ON `OrderItem`
FOR EACH ROW
BEGIN
DELETE FROM `Price` WHERE ID = old.PRICE_ID;
END$$