Pergunta

I have a Microsoft SQL Database with 2 tables: dog and cat.

"dog" table has a primary key column called "food", which is related to a column called "food" as well in the "cat" table, which acts as the foreign key.

The relationship between the tables has an "on delete cascade" rule set, so when I delete a row from "dog" table, the relveant rows from "cat" table should be deleted as well.

But the rows in "cat" table do net get deleted, they stay. I use the Microsoft SQL Database manager to delete the row in "dog" table.

Any idea why this happens? do I need to use a special delete sql command to delete a row in this manner?

//edit

the script for the tables is:

USE [VELES]
GO
/****** Object:  Table [dbo].[Periods]    Script Date: 01/18/2011 14:52:19 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Periods](
    [PeriodID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
    [PeriodName] [nvarchar](50) COLLATE Hebrew_CS_AS NULL,
    [PeriodStartDate] [smalldatetime] NOT NULL,
    [PeriodEndDate] [smalldatetime] NOT NULL,
 CONSTRAINT [PK_Periods] PRIMARY KEY CLUSTERED 
(
    [PeriodID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]


USE [VELES]
GO
/****** Object:  Table [dbo].[Exams]    Script Date: 01/18/2011 14:55:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Exams](
    [ExamID] [int] IDENTITY(1,1) NOT NULL,
    [ExamUserID] [char](7) COLLATE Hebrew_CS_AS NOT NULL,
    [ExamBase] [tinyint] NOT NULL,
    [ExamUserTimesAccessed] [tinyint] NULL,
    [ExamMaxTimesToOpen] [tinyint] NOT NULL,
    [ExamUserLastTimeOpened] [datetime] NULL,
    [ExamUserLastTimeFinished] [datetime] NULL,
    [ExamTimeToFinish] [int] NOT NULL,
    [ExamPassGrade] [int] NOT NULL,
    [ExamPeriod] [int] NOT NULL,
    [ExamUserRank] [tinyint] NULL,
 CONSTRAINT [PK_Exams] PRIMARY KEY CLUSTERED 
(
    [ExamID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
USE [VELES]
GO
ALTER TABLE [dbo].[Exams]  WITH CHECK ADD  CONSTRAINT [FK_Exams_Bases] FOREIGN KEY([ExamBase])
REFERENCES [dbo].[Bases] ([BaseID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Exams]  WITH NOCHECK ADD  CONSTRAINT [FK_Exams_Periods] FOREIGN KEY([ExamPeriod])
REFERENCES [dbo].[Periods] ([PeriodID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Exams]  WITH NOCHECK ADD  CONSTRAINT [FK_Exams_Users] FOREIGN KEY([ExamUserID])
REFERENCES [dbo].[Users] ([UserID])
ON UPDATE CASCADE
ON DELETE CASCADE
NOT FOR REPLICATION 
GO
ALTER TABLE [dbo].[Exams] CHECK CONSTRAINT [FK_Exams_Users]
GO
ALTER TABLE [dbo].[Exams]  WITH CHECK ADD  CONSTRAINT [UserRanks_Exams_FK1] FOREIGN KEY([ExamUserRank])
REFERENCES [dbo].[UserRanks] ([RankID])
ON UPDATE CASCADE
ON DELETE CASCADE
Foi útil?

Solução

I've solved the problem.

In the relationship window, there was an option called Enforce Foreign Key Constraint, which was set to "No". I set it to "Yes" and now row deletion works well.

Outras dicas

Can you show your table structure more concretely? It sound like you have the PK/FK the wrong way around.

Deleting the FK part (child) does not do anything to the PK record (parent). Only when you delete the PK records does it cascade to the child records that link to it.

Are you sure the column food in dog is the primary key of dog? If you have a table called food, then it's column food should be the primary key of food and a foreign key of dog (and cat as well). Then with on delete cascade deletions on food will cause the corresponding rows on dog and cat to be deleted.

For people using SQL Server Management Studio:

I've absolutely seen cases where the UI has got out of sync with the DB, even if it you refreshed the keys list or opened a completely new instance.

For my case I have an Order which has DiscountedItem child items.

The way to check if things are out of sync is to right click on FK_DiscountedItem_Order and select Script Key as CREATE To Clipboard and then examine what you get :

You should get something like this :

ALTER TABLE [dbo].[DiscountedItem]  WITH NOCHECK ADD  CONSTRAINT    [FK_DiscountedItem_Order] FOREIGN KEY([OrderId])
REFERENCES [dbo].[Order] ([OrderId])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[DiscountedItem] CHECK CONSTRAINT [FK_DiscountedItem_Order]
GO

Where you can clearly see DELETE CASCADE.

If you get something like the following, then the cascade rule isn't actually active despite what the UI may say :

ALTER TABLE [dbo].[DiscountedItem]  WITH CHECK ADD  CONSTRAINT [FK_DiscountedItem_Order] FOREIGN KEY([OrderId])
REFERENCES [dbo].[Order] ([OrderId])
GO

I just deleted it (had to actually delete it twice) and recreated it to get the correct SQL.

You may need to run something like this to check for 'orphaned' child rows :

select * from DiscountedItem where DiscountedItem.orderid not in (select orderid from [order])

And then if it is safe to do so :

delete from DiscountedItem where DiscountedItem.orderid not in (select orderid from [order])

Why did this happen?

I just added the constraint and immediately got a foreign key error because I had orphaned rows. Something then got confused and it thought cascade was enabled.

So before creating a new constraint in the UI I recommend you always check first for orphaned rows. You will have to delete them anyway if they exist.

If the cat table is the key for the foreign key, then deleting a row from dog will not delete a row from cat, rather it would work the other way around.

This seams to work just fine.

delete from Periods where PeriodID = 1

will delete one row from Periods and all rows from Exams that have ExamPeriod = 1

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top