3

我必须创建一个 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 的顺序完成的——但我需要确定记录在状态表中的年龄的字段。所以我不能在主表之前从逻辑上删除状态表,但我也不能反过来做。对于运行日志表,我可以使用它:

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 但没有新的存储过程,我不知道该怎么做。有什么建议么?

4

1 回答 1

2

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

哪个应该让您按照需要的顺序进行删除。这假设 run_id 是 Status 的 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 语句给我带来了很多快乐 :-)

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;
于 2013-07-11T23:07:54.627 回答