Cannot create second cascading FK relationship - sql

I have the following tables:
CREATE TABLE [dbo].[Memberships](
[MembershipId] [int] IDENTITY(1,1) NOT NULL,
[GroupId] [int] NOT NULL,
[UserId] [int] NOT NULL,
[IsUserAdmin] [bit] NOT NULL
)
CREATE TABLE [dbo].[Gifts](
[GiftId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[MembershipId] [int] NOT NULL,
[ClaimedByMembershipId] [int] NULL
)
A membership can have many gifts associated with it. When a membership is deleted, I need to do two things:
Delete any gifts associated with that MembershipId.
For any records with ClaimedByMembershipId equal to the MembershipId of the Membership being deleted, set ClaimedByMembershipId to NULL.
I'm attempting to implement this cascading through Management Studio's UI. I can accomplish #1 by the following:
ALTER TABLE [dbo].[Gifts] WITH CHECK ADD CONSTRAINT [FK_Gifts_Memberships]
FOREIGN KEY([MembershipId])
REFERENCES [dbo].[Memberships] ([MembershipId])
ON DELETE CASCADE
GO
For #2, I'm unable to save the table after creating the key which I believe would look something like this:
ALTER TABLE [dbo].[Gifts] WITH CHECK ADD CONSTRAINT [FK_Gifts_Memberships1]
FOREIGN KEY([ClaimedByMembershipId])
REFERENCES [dbo].[Memberships] ([MembershipId])
ON NULL CASCADE
GO
I get the following error:
'Memberships' table saved successfully
'Gifts' table
- Unable to create relationship 'FK_Gifts_Memberships1'.
Introducing FOREIGN KEY constraint 'FK_Gifts_Memberships1' on table 'Gifts' may cause cycles
or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify
other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
Thanks in advance.

Well it's exactly like the error says. You can't create cyclical cascade paths. If TableA can cause a cascading delete on TableB, then TableB cannot cause cascading deletes on TableA. Period. Even if in your specific case it logically seems like it should be ok, SQL Server won't allow it. No option to override.
Best you can do is handle your #2 requirement with a trigger.

Related

How can I define a UNIQUE constraint that applies to multiple columns in a DataSet table?

I have the following table defined in a .sql script file.
CREATE TABLE [HwComponent](
[HwComponentId] [int] NOT NULL,
[HwComponentTypeId] [int] NOT NULL,
[ManufactureId] [int] NOT NULL,
[SerialNumber] [nvarchar](100) NOT NULL,
[AssignmentType] [nvarchar](1000) NOT NULL,
[IsFunctional] [nvarchar](10) NOT NULL,
[Note] [nvarchar](4000) NULL,
CONSTRAINT [PK_HwComponent] PRIMARY KEY ([HwComponentId]),
CONSTRAINT (FK1_HwComponent] FOREIGN KEY ([HwComponentTypeId]) REFERENCES [HwComponentType] ([HwComponentTypeId)] ON DELETE NO ACTION ON UPDATE NO ACTION
CONSTRAINT (FK2_HwComponent] FOREIGN KEY ([HwComponentTypeId], [ManufactureId]) REFERENCES [HwComponentTypeManufacturerInfo] ([HwComponentTypeId], [ManufactureId]) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT (UI1_HwComponent] UNIQUE ([HwComponentTypeId], [ManufactureId], [SerialNumber]))
GO
I now need to define a new table in the DataSet Designer to match.
I believe I have everything defined correctly, except the UNIQUE constraint that requires all 3 columns be considered together as the unique constraint.
How do I define the UNIQUE constraint for this table in the DataSet Designer?
SQL CE Service 4.0 SP1:
VS Prof 2017 - Version 15.8.7
Your code should work if properly formatted. You have parens where you shouldn't:
CREATE TABLE [HwComponent](
[HwComponentId] [int] NOT NULL,
[HwComponentTypeId] [int] NOT NULL,
[ManufactureId] [int] NOT NULL,
[SerialNumber] [nvarchar](100) NOT NULL,
[AssignmentType] [nvarchar](1000) NOT NULL,
[IsFunctional] [nvarchar](10) NOT NULL,
[Note] [nvarchar](4000) NULL,
CONSTRAINT PK_HwComponent PRIMARY KEY ([HwComponentId]),
CONSTRAINT FK1_HwComponent FOREIGN KEY ([HwComponentTypeId]) REFERENCES [HwComponentType] ([HwComponentTypeId)] ON DELETE NO ACTION ON UPDATE NO ACTION
CONSTRAINT K2_HwComponent FOREIGN KEY ([HwComponentTypeId], [ManufactureId]) REFERENCES [HwComponentTypeManufacturerInfo] ([HwComponentTypeId], [ManufactureId]) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT UI1_HwComponent UNIQUE ([HwComponentTypeId], [ManufactureId], [SerialNumber])
);
I would advise you to get rid of all the square braces. They just make the code harder to write and to read and to modify.
Does this work for you?
CREATE UNIQUE INDEX ixYourConstraint ON HwComponent (col1, col2);
This similar post might be of help to you:
MsSql Compact, unique constraint on two and more columns
Thanks Algef and Gordon for you responses.
Sorry about the confusion. My bad. :-)
The SQL sample works fine. I used it as an example only. I actually need to represent this table exactly using the DataSet Designer in VS. The table should look something like the following when done.
HwComponent Table in the DataSet Designer
My problem is I'm not having success in defining the UNIQUE group properly in the DataSet Designer.
I need to define a UNIQUE GROUP that consists of the HwComponentTypeId, ManufactureId and SerialNumber columns.
Any ideas?
Thanks again for any help

Composite Keys Constraints

I am creating a database for handbag shopping website in which i have a table called dbo.ProductMatching
CREATE TABLE [dbo].[ProductMatching](
[ProductMatchingID] [int] NOT NULL IDENTITY, -- This can be Made Primary Key but i want to use composite keys
[MainProductID] [int] NOT NULL,
[MainProductColourID] [int] NOT NULL,
[ReferenceProductID] [int] NULL,
[ReferenceProductColourID] [int] NOT NULL,
[CreatedOn] [datetime] NOT NULL,
[UpdatedOn] [datetime] NOT NULL
) ON [PRIMARY]
What i want to do is Make (MainProductID,MainProductColourID) unique and for each this combination i want to make combination of (ReferenceProductID,ReferenceProductColourID) unique also.
e.g suppose i have combination of (MainProductID,MainProdcutColourID) = (1,1) it referes to (ReferenceProductID,ReferenceProductColourID) = (2,2) Then (1,1) can not refer to another (2,3) combination.. i cant make the whole four keys composite keys because it would allow reference (1,1) to (2,3) combination..
i know i can just make exists statement when inserting data or make a before insert trigger or update trigger for data consistency but what i want to know if this can be done with using composite keys.. if not what are other available options...
If I understand the problem then two simple unique constraints
MainProductID,MainProductColourID
and
MainProductID,ReferenceProductID
And I would use
MainProductID,MainProductColourID as a composite PK
(that will satisfy that unique constraint)
If that is wrong then please show more examples that are correct
And more that are incorrect with a reason

Adding Composite Foreign Key

I am having a problem adding a foreign key constraint to SQL 2008 that is based on a composite primary key in another table. I have followed some directions based on a few posts on here, but haven't been able to get it to work.
I have two tables:
CREATE TABLE [Staging].[ActivityLog](
[ActivityLogId] [int] IDENTITY(1,1) NOT NULL,
...
[ActivityLogType] [varchar](10) NOT NULL,
[ActivityLogSubType] [varchar](10) NOT NULL,
CONSTRAINT [PK_ActivityLog] PRIMARY KEY CLUSTERED
(
[ActivityLogId] ASC
))
and
CREATE TABLE [Staging].[ActivityLogTypeSubType](
[ActivityLogType] [varchar](10) NOT NULL,
[ActivityLogSubType] [varchar](10) NOT NULL,
CONSTRAINT [PK_ActivityLogTypeSubType] PRIMARY KEY CLUSTERED
(
[ActivityLogType] ASC,
[ActivityLogSubType] ASC
))
GO
I am trying to add a foreign key like this:
ALTER TABLE Staging.ActivityLog
ADD CONSTRAINT FK_ActivityLog_ActivityLogTypeSubType
FOREIGN KEY(ActivityLogType, ActivityLogSubType)
REFERENCES Staging.ActivityLogTypeSubType(ActivityLogType, ActivityLogSubType)
I get this error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_ActivityLog_ActivityLogTypeSubType". The conflict occurred in database "HMDB_DEV", table "Staging.ActivityLogTypeSubType".
I have verified that this FK doesn't already exist.
I apologize for the lengthy post. Any help would be greatly appreciated.
Thanks,
James
Have you verified data to match FK logic?

How can I stop the delete on a parent if a child entity that references that parent exists?

I have the following DDL that I am using with SQL Server 2012:
CREATE TABLE Subject (
[SubjectId] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (50) Not NULL,
CONSTRAINT [PK_Subject] PRIMARY KEY CLUSTERED ([SubjectId] ASC)
)
CREATE TABLE Topic (
[TopicId] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
[SubjectId] INT NOT NULL,
CONSTRAINT [PK_Topic] PRIMARY KEY CLUSTERED ([TopicId] ASC)
)
ALTER TABLE [Topic] WITH CHECK ADD CONSTRAINT [FK_TopicSubject]
FOREIGN KEY([SubjectId]) REFERENCES [Subject] ([SubjectId])
ON DELETE CASCADE
CREATE TABLE SubTopic (
[SubTopicId] INT IDENTITY (1, 1) NOT NULL,
[TopicId] INT NOT NULL,
[Name] NVARCHAR (4000) Not NULL,
CONSTRAINT [PK_SubTopic] PRIMARY KEY CLUSTERED ([SubTopicId] ASC)
)
ALTER TABLE [SubTopic] WITH CHECK ADD CONSTRAINT [FK_SubTopicTopic]
FOREIGN KEY([TopicId]) REFERENCES [Topic] ([TopicId])
ON DELETE CASCADE
When I try to run the scripts I get the following message:
{"Introducing FOREIGN KEY constraint 'FK_TopicSubject'
on table 'Topic' may cause cycles or multiple cascade paths.
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
or modify other FOREIGN KEY constraints.\r\nCould not create constraint.
See previous errors."}
What I really need is for when a person tries to DELETE a subject when there are topics for the delete to fail. If I include neither DELETE ON CASCADE or DELETE NO ACTION then will this happen. If not then how can I stop the delete on subject happening if there are Topics for that subject?
Short answer is: If you don’t want cascade updates and deletions then use ON DELETE NO ACTION. Same applies for Update.
Here is a copy from MSDN article (it’s SQL Server 2000 but same rules still apply)
ON DELETE NO ACTION
Specifies that if an attempt is made to delete a row with a key referenced by foreign keys in existing rows in other tables, an error is raised and the DELETE is rolled back.
ON UPDATE NO ACTION
Specifies that if an attempt is made to update a key value in a row whose key is referenced by foreign keys in existing rows in other tables, an error is raised and the UPDATE is rolled back.
Please refer to this link. It has given a detail explanation of this error, and also has suggested to create a trigger as an alternative.
Foreign key constraint may cause cycles or multiple cascade paths?

sql delete cascade not working

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
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.
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.
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; --should be seeing this!
ALTER TABLE [dbo].[DiscountedItem]
CHECK CONSTRAINT [FK_DiscountedItem_Order];
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]);
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.
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.
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