【问题标题】:deleting multiple records from two tables从两个表中删除多条记录
【发布时间】:2010-12-27 17:43:20
【问题描述】:

我有两个表,分别称为 TableA 和 TableB。

TableA 有以下字段:

TableA_ID
FileName

TableB 有以下字段:

TableB_ID
TableA_ID
CreationDate

TableA_ID 字段上的两个表之间存在外键链接

我需要从两个表中删除记录。我需要查看 TableB 上的“CreationDate”,如果它在某个日期之后,请删除该记录。我还需要删除 TableA 中与 TableB 中的记录具有相同 TableA_ID 的记录

TableB 中可能有多个记录使用 TableA_ID(一对多关系)。所以如果TableB中的条目仍然使用它,我无法删除TableA中的记录。

我知道这不能在单个语句中完成,但很高兴在事务中完成。我的问题是我不知道该怎么做。我正在使用 MS SQL Server 2008。如果可能,我不想使用触发器。

【问题讨论】:

    标签: sql sql-server delete-row


    【解决方案1】:

    表A中是否有记录而表B中没有匹配记录?如果没有,那么我们知道在TableB中删除后,我们可以删除TableA中任何不匹配的记录:

    begin transaction
    delete from TableB
    where CreationDate > @SomeDate
    
    delete from TableA
    where TableA_ID not in (select TableA_ID from TableB)
    end transaction
    

    否则:

    begin transaction
    -- Save the TableA_IDs being deleted:
    select distinct TableA_ID
    into #TableA_Delete
    from Table_B
    where CreationDate > @Somedate
    
    -- Depending on the expected size of #TableA_Delete, you may want 
    -- to create an index here, to speed up the delete from TableA.
    
    delete from TableB
    where CreationDate > @SomeDate
    
    delete from TableA
    where TableA_id in (select TableA_Id from #TableA_Delete)
    and TableA_id not in (select TableA_id from TableB)
    commit transaction
    

    注意 以上两种解决方案都需要添加错误处理。

    另外,请参阅 NYSystemsAnalyst 了解另一种临时存储 ID 的方法。

    【讨论】:

    • +1 Shannon 的解决方案解决了我下面的解决方案中 WHERE...GROUP BY 子句的缺点。
    • 由于最后一个“Where”语句,由于某种原因无法保存。我会摆弄它,但任何人都可以发现是否缺少某些东西吗?
    • @Retrocoder: 抱歉,最后一个地方太乱了,没用。编辑修复。
    【解决方案2】:

    编辑:抱歉,我没有看到您的问题部分说明如果 TableA 条目在 TableB 中有多个记录,则需要保留它们。改用这个:

    /* Table valued variable to hold Table A IDs to be deleted. */
    DELCARE @IDs AS table
    (
        ID int
    );
    
    /* Get the TableA IDs that are subject to deletion. */
    INSERT INTO @IDs (
        ID
    )SELECT TableA_ID
    FROM TableB
    WHERE CreationDate >= @MyCreationDate)
    GROUP BY TableA_ID
    HAVING (COUNT(TableA_ID) = 1); /* Only get IDs that appear once in TableB */
    
    /* Delete the TableB records. */
    DELETE b
    FROM TableB AS b
    WHERE CreationDate >= @MyCreationDate);
    
    /* Delete the TableA records. */
    DELETE a
    FROM TableA AS a
        INNER JOIN @IDs AS c ON (a.TableA_ID = c.ID);
    

    您应该将所有这些包装在一个事务中以确保数据完整性。

    【讨论】:

    • 填充@ID 的选择不起作用。 1) OP 没有说明 TableB 中没有多行被每个 TableA_ID 删除。 2)HAVING子句发生在(逻辑上)WHERE子句之后,所以如果有TableB记录没有被删除,HAVING子句就看不到它们,也不会计数。
    • 1) 原帖指出“TableB 中可能有几条记录使用 TableA_ID(一对多关系)。所以如果 TableB 中的条目仍然使用,我无法删除 TableA 中的记录它。”因此,如果表 B 中存在未被删除的条目,则无法删除表 A 记录。
    【解决方案3】:

    删除父行时,参照完整性应删除子行。确保您已启用级联删除。

    否则,您将不得不放入两个删除语句,一个用于子记录,一个用于父记录。

    DELETE FROM TableB INNER JOIN TableA ON TableA.TableAID = TableB.TableAID WHERE CreationDate >= SomeDate
    
    DELETE FROM TableA WHERE TableAID=SomeID
    

    【讨论】:

    • 他不能依赖引用的 DELETE 级联,因为如果 TableB 条目的 CreationDate 正常,他不想删除它们。级联删除将清除它们。另外,您发布的两条语句从 TableB 中删除了正确的条目,但是 SomeID 来自哪里?
    • SomeID 只是一个参数。我假设他/她对 SQL 中的参数有所了解。
    • 另外还有很多不使用级联删除的原因。最好不要依赖于能够设置它,因为它会造成严重的性能问题。
    猜你喜欢
    • 2011-07-15
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    相关资源
    最近更新 更多