Sql server 删除了周围的约束

Sql server 删除了周围的约束,sql-server,tsql,Sql Server,Tsql,我必须创建一个SQL query.SQL文件,由SQLServer中的sqlcmd.exe运行,以删除特定天数内的所有记录。然而,我发现自己被如何绕过外键约束所迷惑。为了说明问题,这里有三个具有类似关系的表。请注意,这是伪代码: CREATE TABLE runlog( row_id int identity(1,1) NOT NULL, run_id nvarchar(25) NULL FOREIGN KEY REFERENCES status(run_id), mas

我必须创建一个SQL query.SQL文件,由SQLServer中的sqlcmd.exe运行,以删除特定天数内的所有记录。然而,我发现自己被如何绕过外键约束所迷惑。为了说明问题,这里有三个具有类似关系的表。请注意,这是伪代码:

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的顺序进行的,但我需要确定记录的保存时间的字段在status表中。因此,我不能在主表之前从状态表中逻辑删除,但我也不能以另一种方式进行删除。 对于运行日志表,我可以使用以下内容:

delete from runlog 
inner join status on status.run_id = runlog.run_id 
where status.status_date <= DATEADD(DAY, -30, GETDATE())
要选择所需的主id,我可以使用:

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

然后,如果有一种方法可以缓存这个列表,我可以使用它从status中删除列表,然后从master中删除列表,但如果没有新的存储过程,我不知道如何执行此操作。有什么建议吗

您可以在delete语句中使用output子句将删除的数据插入到表变量中

这将允许您按照需要的顺序执行删除操作。。这假设run_id是Status的主键,master_id是master的主键

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 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;

如何使用master_id删除主表中状态不匹配的所有记录?这样就不需要缓存状态表的记录,这是一个想法。但我不想错误地删除一些原本不应该删除的东西。从技术上讲,在主记录的状态存在之前,可以在主记录中创建记录。确实,您可以将statusmaster\u id中的外键更改为级联删除。因此,当您删除master中的记录时,它将删除状态中的记录。我想我需要创建一个临时表来保存master_id结果,然后与该表连接以执行删除,然后删除该表。。。但是,我不认为运行脚本的用户可以创建table为什么不能首先将要删除的记录列表缓存到表变量/temp表中?