Question

I have two tables called TableA and TableB.

TableA has the following fields:

TableA_ID
FileName

TableB has the following fields:

TableB_ID
TableA_ID
CreationDate

There is a foreign key link between the two tables on the TableA_ID field

I need to delete records from both tables. I need to look at the “CreationDate” on TableB and if it’s after a certain date, delete that record. I will also need to delete the record in TableA with the same TableA_ID as the record in TableB

There may be several records in TableB that use the TableA_ID (a one to many relationship). So I can’t delete the record in TableA if entries in TableB still use it.

I know this can’t be done in a single statement but am happy to do it in a transaction. The problem I have is I’m not sure how to do this. I’m using MS SQL server 2008. I don’t want to use triggers if possible.

Was it helpful?

Solution

Can there be records in TableA with no matching record in TableB? If not, then we know after we delete from TableB, we can delete any non-matching records in TableA:

begin transaction
delete from TableB
where CreationDate > @SomeDate

delete from TableA
where TableA_ID not in (select TableA_ID from TableB)
end transaction

Otherwise:

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

NOTE Both above solutions need error handing added.

Also, see NYSystemsAnalyst for another method of storing the IDs temporarily.

OTHER TIPS

Referential integrity should delete the child rows when the parent is deleted. Make sure you have cascade deletes enabled.

Otherwise you would have to put in two delete statements one for the child records and one for the parent record.

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

DELETE FROM TableA WHERE TableAID=SomeID

Edit: Sorry, I didn't see the part of your question stating the need to keep the TableA entries if they have multiple records in TableB. Use this instead:

/* 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);

You should wrap all of this in a transaction to ensure data integrity.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top