我必须创建一个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中删除,但是没有新的存储过程我不知道如何做到这一点。有什么建议?
答案 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;