2011-09-20 86 views
1

假设我有一个已经包含'IsDelete Char(1)'列的表。 每当我对这个表进行删除处理时,我不会做出实际的删除命令。SQL删除更新外键主键约束

eg. DELETE FROM TableName 

但我做了更新命令。

eg. UPDATE TableName SET IsDelete = '1' ..... 

所以,如果我想为这个表做参照完整性,我不知道如何做到这一点。 因为我没有做出实际的删除命令。 请解释我。

回答

0

首先,最好使用bit数据类型为IsDelete列。

至于参照完整性,您可以使用REFERENCES以及不使用IsDelete列。我没有看到任何问题。

加盟申请表,你可以使用:

SELECT * 
FROM tbl1 
    JOIN tbl2 ON tbl1.id=tbl2.id 
        and tbl1.IsDelete=0 
        and tbl2.IsDelete=0 

编辑

至于部门和员工。

在现实生活中,关闭部门并不意味着解雇员工。通常情况下,您需要先将员工移至其他部门(或解雇他们),然后关闭部门。在这种情况下,FOREIGN KEYS不会有任何问题。

但是在现实生活中,经常发生这样的情况,部门首先关闭,然后管理层认为如何处理人员。

在这种情况下,如果您有以下参考,您仍然不会有任何问题。

ALTER TABLE [Employees] WITH CHECK ADD CONSTRAINT [FK_Employees_Departments] FOREIGN KEY([Department_id]) 
REFERENCES [Departments] ([Department_id]) 
+0

我想说的是让我们假设有2个表叫做Department和Employee。两个表都有IsDelete列。所以,如果我首先删除部门“例如更新部门设置Department.IsDelete = 1其中....”。如果已删除部门已存在于员工,它可能发生打破部门和员工之间的参照完整性。所以在这种情况下,我该如何做出参照完整性约束。因为我不想编写这么多的代码来检查。 –

+0

查看Bogdan Sahlean的回答,他举了一个很好的例子。 –

+0

@MyatThu我编辑了我的答案。 –

2

检查与SQL Server测试了这个声明溶液(见源代码注释):

CREATE TABLE dbo.SalesOrder 
(
    SalesOrderID INT IDENTITY(1,1) 
    ,OrderDate DATETIME NOT NULL 
    ,IsDeleted CHAR(1) NOT NULL DEFAULT 'N' 
    ,CONSTRAINT PK_SalesOrder PRIMARY KEY (SalesOrderID) 
    ,CONSTRAINT CK_SalesOrder_IsDeleted CHECK(IsDeleted IN ('Y','N')) 
); 

CREATE TABLE dbo.SalesOrderDetail 
(
    SalesOrderDetailID INT IDENTITY(1,1) 
    ,Qty DECIMAL(8,2) NOT NULL 
    ,UnitPrice DECIMAL(8,2) NOT NULL 
    ,IsDeleted CHAR(1) NOT NULL DEFAULT 'N' 
    ,SalesOrderID INT NOT NULL 
); 

--We need this index to create the next foreign key constraint 
CREATE UNIQUE NONCLUSTERED INDEX IUN_SalesOrder_SalesOrderID_IsDeleted 
ON dbo.SalesOrder(SalesOrderID, IsDeleted); 

--If we "delete" (UPDATE dbo.SalesOrder SET IsDeleted = "Y" ...) a row from dbo.SalesOrder table, 
--then this modification (... SET IsDeleted = "Y" ...) will be propagated to dbo.SalesOrderDetail table 
--because of ON UPDATE CASCADE clause 
ALTER TABLE dbo.SalesOrderDetail 
ADD CONSTRAINT FK_SalesOrderDetail_SalesOrder_SalesOrderID_IsDeleted 
FOREIGN KEY (SalesOrderID, IsDeleted) REFERENCES dbo.SalesOrder(SalesOrderID, IsDeleted) 
ON UPDATE CASCADE; 

INSERT dbo.SalesOrder (OrderDate) 
SELECT '20110101' 
UNION ALL 
SELECT '20110202' 
UNION ALL 
SELECT '20110303'; 

INSERT dbo.SalesOrderDetail (Qty, UnitPrice, SalesOrderID) 
SELECT 1,10,1 UNION ALL SELECT 1,11,1 UNION ALL SELECT 1,12,1 
UNION ALL 
SELECT 2,20,2 
UNION ALL 
SELECT 3,30,3 UNION ALL SELECT 3,31,2; 

SELECT * 
FROM dbo.SalesOrder 
SELECT * 
FROM dbo.SalesOrderDetail 

--Test "DELETE"/UPDATE statement 
UPDATE dbo.SalesOrder 
SET  IsDeleted = 'Y' 
WHERE SalesOrderID = 1; 

--Now, we can check SalesOrderDetail rows ([Status] values WHERE [SalesOrderID]=1) 
SELECT * 
FROM dbo.SalesOrder 
SELECT * 
FROM dbo.SalesOrderDetail 

DROP TABLE dbo.SalesOrderDetail;  
DROP TABLE dbo.SalesOrder; 
+0

假设我将您的代码更改为FOREIGN KEY(SalesOrderID,IsDeleted)REFERENCES dbo.SalesOrder(SalesOrderID,IsDeleted) ON UPDATE NO ACTION;因为我想只为SaleOrder表禁止删除操作。然后,SaleOrder表是okey,因为它在删除时返回外键限制消息(SET IsDeleted ='Y')。但不幸的是,SaleOrderDetail无法删除(SET IsDeleted ='Y')。所以,如果你有其他解决方案,请给我建议。 –

+0

是@Bogdan我已经运行,因为你告诉UPDATE dbo.SalesOrderDetail SET IsDeleted ='Y'WHERE SalesOrderID = 1;但是我得到消息“UPDATE语句与参考约束冲突”FK_SalesOrderDetail_SalesOrder_SalesOrderID_IsDeleted“冲突发生在数据库”DBTest_MT“,表”dbo.SalesOrderDetail“中。” –

+0

如果将FK定义从ON UPDATE CASCADE更改为ON UPDATE NO ACTION,你会得到那个错误。这个新的规范(“更新不行动”)与参照完整性概念本身冲突/矛盾。例如,您不能有两个'SalesOrderDetail(SalesOrderID = 101; IsDedeleted ='Y'; Qty = 10&SalesOrderID = 101; IsDedeleted ='Y'; Qty = 20)'SalesOrder(SalesOrderID = 101;请将isDeleted = 'N')'。 –

1

如果你不想从表中删除以往的记录,然后更改权限表所以除了sys_admin之外,没有其他人可以删除。

通常当您添加一个IS_Deleted列时,最好重命名该表,然后创建一个只有选择活动记录的旧表名的视图。这将防止你的代码中断。

如果您希望在桌面上执行删除操作时发生更新,则通过触发器完成更新。在SQL Server触发器上操作整个批处理,因此请确保触发器可以处理多行删除。