删除约束

时间:2013-07-11 19:38:58

标签: sql-server tsql

我必须创建一个SQL查询(由SQL Server中的sqlcmd.exe运行.sql文件)以删除超过一定天数的所有记录。但是我发现自己对如何解决外键约束感到困惑。为了说明这里的问题,有三个具有相似关系的表(注意这是伪代码):

CREATE TABLE runlog(
    row_id int identity(1,1) NOT NULL,
    run_id nvarchar(25) NULL FOREIGN KEY REFERENCES status(run_id),
    master_id nvarchar(25) NULL FOREIGN KEY REFERENCES master(master_id),
)

CREATE TABLE status(
    run_id nvarchar(25) NOT NULL,
    master_id nvarchar(25) NULL FOREIGN KEY REFERENCES master(master_id),
    status_date datetime NULL,
)

CREATE TABLE master(
    master_id nvarchar(25) NOT NULL,
)

通常在runlog,status,master的命令中完成删除 - 但是我需要确定状态表中记录的年龄。所以我不能在主表之前从状态表中逻辑删除,但我不能以相反的方式执行。 对于runlog表我可以使用它:

delete from runlog 
inner join status on status.run_id = runlog.run_id 
where status.status_date <= DATEADD(DAY, -30, GETDATE())

要选择所需的master_id,我可以使用:

select master_id from status 
where status.status_date <= DATEADD(DAY, -30, GETDATE())

然后,如果有一种方法可以缓存此列表,我可以使用它从状态中删除列表,然后从master中删除,但是没有新的存储过程我不知道如何做到这一点。有什么建议?

1 个答案:

答案 0 :(得分:2)

您可以在delete语句中使用output子句将已删除的数据插入表变量中 http://msdn.microsoft.com/en-us/library/ms177564.aspx

哪个应该允许你按照你需要的顺序进行删除..这假设run_id是状态的PK而master_id是master的PK ..

BEGIN TRANSACTION;
BEGIN TRY
    declare @runIds Table (id nvarchar(25))
    declare @masterIds Table (id nvarchar(25))

    delete rl 
    OUTPUT DELETED.run_id into @runids
    from runlog as rl
    inner join StatusTbl on StatusTbl.run_id = rl.run_id 
    where StatusTbl.status_date <= DATEADD(DAY, -30, GETDATE())

    delete from StatusTbl 
    OUTPUT DELETED.master_id into @masterIds
    where run_id in (select id from @runIds)

    delete from MasterTbl 
    where master_id in (select id from @masterIds)
END TRY
BEGIN CATCH
    SELECT 
    ERROR_NUMBER() AS ErrorNumber
    ,ERROR_SEVERITY() AS ErrorSeverity
    ,ERROR_STATE() AS ErrorState
    ,ERROR_PROCEDURE() AS ErrorProcedure
    ,ERROR_LINE() AS ErrorLine
    ,ERROR_MESSAGE() AS ErrorMessage;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

修改

我意识到你的场景纯粹是假设,但你也可以使用MERGE进行连接删除,我非常肯定建议你做连接样式更新/删除。我发现编写MERGE语句给我带来了很多快乐: - )

MERGE runlog AS target
    USING (select run_id, status_date FROM StatusTbl where StatusTbl.status_date <= DATEADD(DAY, -30, GETDATE())) AS source ([run_id], [status_date])
    ON (target.run_id = source.[run_id])
    WHEN MATCHED THEN DELETE
    OUTPUT DELETED.run_id into @runids;