views:

47

answers:

4
CREATE Table A
(
 AId int ,
 AName varchar(100)
)

CREATE Table B
(
 BId int,
 AId int,
 CId int,
 BName varchar(100)
)

CREATE Table C
(
 CId int,
 CName varchar (100)

)

"A" has foreign key in "B" and "C" also has foreign key in B. Both foreign keys have Cascade delete enabled.

Foreign key :-

/****** Object:  ForeignKey [FK_B_A]    Script Date: 10/28/2010 17:20:16 ******/
ALTER TABLE [dbo].[B]  WITH CHECK ADD  CONSTRAINT [FK_B_A] FOREIGN KEY([AId])
REFERENCES [dbo].[A] ([AId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[B] CHECK CONSTRAINT [FK_B_A]
GO
/****** Object:  ForeignKey [FK_B_C]    Script Date: 10/28/2010 17:20:16 ******/
ALTER TABLE [dbo].[B]  WITH CHECK ADD  CONSTRAINT [FK_B_C] FOREIGN KEY([CId])
REFERENCES [dbo].[C] ([CId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[B] CHECK CONSTRAINT [FK_B_C]
GO

-- Sample data

INSERT INTO A
VALUES (1, 'Ashish')
INSERT INTO A
VALUES (2, 'Sanjay')
INSERT INTO A
VALUES (3, 'Vivek')

INSERT INTO B
VALUES
(1,1,10,'Ashish1')
INSERT INTO B
VALUES
(2,1,11,'Ashish2')
INSERT INTO B
VALUES
(3,1,12,'Ashish3')


INSERT INTO B
VALUES
(4,2,13,'Ashish1')
INSERT INTO B
VALUES
(5,2,14,'Sanjay')
INSERT INTO B
VALUES
(6,3,15,'Vivek')

INSERT INTO C
VALUES
(10, 'Ashish Data1')
INSERT INTO C
VALUES
(11, 'Ashish Data2')

INSERT INTO C
VALUES
(12, 'Ashish Data3')

INSERT INTO C
VALUES
(13, 'Ashish Data4')

INSERT INTO C
VALUES
(14, 'sanjay Data1')

INSERT INTO C
VALUES
(15, 'Vivek Data1')

I thought following would delete all data from all the tables:-

DELETE a FROM A a
INNER JOIN B ON A.AId = B.AId
INNER JOIN C ON B.CId = C.CID

instead I had to write this:-

DELETE a FROM A a
INNER JOIN B ON A.AId = B.AId

DELETE b FROM B b
INNER JOIN C ON B.CId = C.CID

Is there any way to delete all data in s single delete statement?

+1  A: 

Basically, if I understood correctly, you can only delete the data from 'b' and it will delete the data in 'a' and 'c'.

A <-- B [delete] --> C

From the Microsoft website:

ON DELETE CASCADE

Specifies that if an attempt is made to delete a row with a key referenced by foreign keys in existing rows in other tables, all rows containing those foreign keys are also deleted. If cascading referential actions have also been defined on the target tables, the specified cascading actions are also taken for the rows deleted from those tables.

Jason
No, deleting data from C does not delete data from A and B.
ydobonmai
Just been trying to get my head around it, but I think you've answered the problem, but it's because the FK are A->B<-C - or something like that, which stops the cascade going all the way down.
Paul Hadfield
The following does not work as well:- DELETE c FROM C c INNER JOIN B ON C.CId = B.CIdINNER JOIN A ON A.AId = B.AId
ydobonmai
+1 Paul. This is exactly like that. I am wondering If I am missing anything here.
ydobonmai
This also does not work :- DELETE b FROM B bINNER JOIN C ON B.CId = C.CIDINNER JOIN A ON A.AId = B.AId
ydobonmai
What if you try to only delete from b without any joins?
Jason
Deleting from B without joins does not work as well.
ydobonmai
+1  A: 

Cascading delete would mean that when a delete is performed on a parent table then the corresponding rows in child tables which have references to the parent table are also deleted.

So in your case table B is the child table for both table A and table C.

So, you cannot have one delete statement to remove data from all the tables. Instead, you can delete a row from table A and it will remove corresponding child rows from table B.

Similarly, a delete from table C will remove its corresponding child rows from table B.

Edit - THe queries that you have written are deletes without a where clause. So, if you are trying to delete all the rows from table A and table C and there by deleting all referenced rows in table B, you can use this -

DELETE FROM A --deletes all rows in A and corresponding referenced rows in B

DELETE FROM C --deletes all rows in C and corresponding referenced rows in B
Pavanred
Yeah, right. Like the delete statements I have already in my question.
ydobonmai
Added delete statements to my answer
Pavanred
A: 

Hmm, is it possible to change the constraints?

The problem as I see it is that C has a 1 to many with A, and B has a 1 to many with C, so instead of having AId be a foreign key in B, have AId be the foreign key in C, So if you delete a person from A, it'll cascade to C, which will cascade to B. If you delete an item from C, it'll cascade to B, but not A, and if you delete an item from B it wont effect either of the other two tables.

My suggestion:

CREATE TABLE [A] (
    [AId] [int] NOT NULL ,
    [AName] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    CONSTRAINT [PK_A] PRIMARY KEY  CLUSTERED 
    (
        [AId]
    )  ON [PRIMARY] 
) ON [PRIMARY]
GO

CREATE TABLE [C] (
    [CId] [int] NOT NULL ,
    [CName] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    [AId] [int] NULL ,
    CONSTRAINT [PK_C] PRIMARY KEY  CLUSTERED 
    (
        [CId]
    )  ON [PRIMARY] ,
    CONSTRAINT [FK_C_A] FOREIGN KEY 
    (
        [AId]
    ) REFERENCES [A] (
        [AId]
    ) ON DELETE CASCADE 
) ON [PRIMARY]
GO

CREATE TABLE [B] (
    [BId] [int] NOT NULL ,
    [AId] [int] NULL ,
    [CId] [int] NULL ,
    [BName] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    CONSTRAINT [PK_B] PRIMARY KEY  CLUSTERED 
    (
        [BId]
    )  ON [PRIMARY] ,
    CONSTRAINT [FK_B_C] FOREIGN KEY 
    (
        [CId]
    ) REFERENCES [C] (
        [CId]
    ) ON DELETE CASCADE  NOT FOR REPLICATION 
) ON [PRIMARY]
GO

With this setup, Delete From A will clean out all 3 tables in one go.

Edit: you can keep AId in B to make joins easier, but it won't have any thing to do with the delete cascade.

AndyD273
A: 

You cannot delete records from A and C with a single statement because this tables are not in a transitive reference relationship.

If you want to delete all records from A and C that have corresponding records in B, you should use two statements:

DELETE  a
FROM    a
JOIN    b
ON      b.aid = a.aid

DELETE  c
FROM    c
JOIN    b
ON      b.cid = c.cid
Quassnoi
I don't think the join is needed. The foreign key constraint will make sure that data in B is associated with data in A. Well, the join would be required only if you want to delete all records in A and B except rows in A that are not referenced in B.
Pavanred
@Pavan: as I said, this query deletes "all records from `A` and `C` that have corresponding records in `B`"
Quassnoi