views:

54

answers:

4

This is the case. There are 3 tables - state, region and city. If I delete a state with the name "France", I want that all regions and cities belonging to this state be deleted as well. How to do this in T-SQL?

A: 

You can set up the tables for cascading deletes, so you delete the entry from the table where everything is foreign keyed to.

Brett
+2  A: 

The simplest solution is to ensure that you have Cascade Delete enabled on the relationships between the tables.

Create Table State
(
    Code char(2) not null Primary Key
    , ...
)
Create Table Region
(
    Code varchar(10) not null
    , StateCode char(2) not null
    , Constraint FK_Region_State 
        Foreign Key ( StateCode )
        References State( Code )
        On Delete Cascade
)
Create Table City
(
    Name varchar(40) not null
    , StateCode char(2) not null
    , RegionCode varchar(10) not null
    , Constraint FK_City_State 
        Foreign Key ( StateCode )
        References State( Code )
        On Delete Cascade
    , Constraint FK_City_Region
        Foreign Key ( StateCode )
        References State( Code )
        On Delete Cascade
)

If for some reason you cannot enable Cascade Delete, then you will have to enforce this rule via a Trigger on the State table. (Btw, a "State" named France?)

Thomas
Neither a trigger or cacade delete is a good idea. What happens when you cascade delete a record with thousands or millionof child records? Oh yeah, the table gets locked up and no one can work. It is very bad to enforce this through cascade delte unless you know the number of records will be small. Further, it loses the idea of not wanting to delete if child records are still there. This is an important thing, as many times the existnace of a child record tells you that you should not be deleting the parent.
HLGEM
@HLGEM - A. There aren't thousands of cities or countries in existence. B. Let's suppose there are trillions of rows dependent on your "France" row and you need to delete it. It still has to be done in a transaction to maintain data integrity. All that Cascade Delete is doing is saving you the trouble of writing multiple delete queries in a transaction.
Thomas
@HLGEM - I'm in no way suggesting that CD should be used everywhere however if it is the case that you always want child rows deleted when the parent row is deleted, then cascade delete makes sense. Perhaps with a trillion rows it might not for performance reasons but regardless whether you do depends on the problem, schema and business rules.
Thomas
+1  A: 

I'm assuming you haven't set up cascading deletes, so you've got to work your way from the bottom up: delete cities first, then regions, then state.

delete from c
    from city c
        inner join region r
            on c.region_id = r.region_id
        inner join state s
            on r.state_id = s.state_id
    where s.state = 'France'

delete from r
    from region r
        inner join state s
            on r.state_id = s.state_id
    where s.state = 'France'

delete from s
    from state s
    where s.state = 'France'
Joe Stefanelli
I know this, but I needed a faster way. As you mentioned the term 'cascading deletes', I will go to MSDN, read about it and return if I have something to ask.
askmo
As mentioned in [Raj More's answer](http://stackoverflow.com/questions/3619103/howto-delete-fk-and-all-dependent-table-entries/3619198#3619198), I'm also personally not a fan of cascading deletes. Like Raj, I prefer to retain control of these operations in my own code.
Joe Stefanelli
+2  A: 

Although Cascade-Delete is the way to go here, I am very uncomfortable setting that up. It feels like a very unsafe thing to do, so I never set up cascading deletes.

I prefer to do it in TSQL

DELETE FROM Cities
WHERE RegionId IN 
(
    SELECT Id
    From Regions
    Where CountryId IN
    (
        Select Id
        From Country
        Where Country = 'France'
    )
)

then delete regions

DELETE FROM Regions
Where RegionId IN
(
    Select Id
    From Country
    Where Country = 'France'
)

then delete countries

DELETE FROM Country
Where Country = 'France'
Raj More
Obviously, you would also want to ensure you do this in a transaction.
Thomas
Strongly agree, cascade delete is a very dangerous thing and can bring your sytem to a halt. I never recommend it's use.
HLGEM
@HLGEM - How would the above three queries encapsulated into a transaction with the equivalent isolation level perform any different than cascade delete?
Thomas
@Thomas, they're not performing any different that a Cascade Delete. But say you've implemented cascade delete in your online store, and you run `delete from shipping_modes where type = 'fedex'`. You just lost all your old orders (admittedly you can get them from backups) but you also lost new orders that hadn't made it into the backup yet. These scenarios just make me jittery.
Raj More
@Raj More - If the delete sp fries all orders when you delete a shipping mode then you are in the same boat as using CD. Just as you wouldn't include that logic when deleting a shipping mode, nor should you enable cascade delete in that scenario. Yes, be cautious but not the the point of being extremist. It is silly not to use CD on invoice line items or order line items for example. As with anything, use it where it makes sense.
Thomas
I agree that it should be used cautiously. But really, when this is implemented, there is no warning mechanism. One delete statement can cause a lot of grief. And more often than not, a developer is not in charge of a production database - someone that doesn't know about the cascade deletes now holds the power to blow away orders.
Raj More
@Raj More - Agreed it should be used cautiously, but again if the delete routine also fries child rows the situation is no different. Cascade deletes and updates are meant to maintain integrity and if a given set of child data is effectively part of its parent (e.g. invoice and order line items) then it makes sense to use cascading DRI.
Thomas
@Thomas, I do not doubt their intent. I am simply wary of their power of destruction.
Raj More