Deleting rows without CASCADE DELETE? - sql

I have a database in SQL Server, where I have one table for customers, and each customer can have multiple bookings, but a booking can belong only to one customer. The point is that I have written an API and then a client side app using WPF, but I just noticed that I cannot delete a customer without actually previously deleting the associated bookings with that customer. My T-SQL looks like this roughly:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Customer](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FullName] [nvarchar](50) NOT NULL,
[DateOfBirth] [date] NOT NULL,
[Phone] [nvarchar](20) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
))
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Booking](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Amount] [decimal](10,2) NOT NULL,
[CustomerId] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
))
ALTER TABLE [dbo].Booking WITH CHECK ADD CONSTRAINT [FK_Booking_Customer] FOREIGN KEY([CustomerId])
REFERENCES [dbo].[Customer] ([Id])
GO
ALTER TABLE [dbo].[Booking] CHECK CONSTRAINT [FK_Booking_Customer]
GO
Then, I have a delete stored procedure defined like this:
CREATE PROCEDURE DeleteCustomer
#Id int
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM [dbo].[Customer]
WHERE Id = #Id
END
GO
But as I said I cannot delete a customer that has existing bookings. One way is surely to use CASCADE DELETE, but I don't want also the bookings to be deleted if the customer is deleted. Any idea how to overcome the problem or any workarounds?

The options I see are:
Make the foreign key column [CustomerId] nullable, and then use on delete set null
Use a soft delete on the Customer table, e.g. a bit column such as IsActive or IsDeleted.
Disable the foreign key: alter table [dbo].Booking nocheck constraint [FK_Booking_Customer]
Drop the foreign key.
In most situations I would implement the soft delete option.

Related

How to set ID value from another table

Let's say I have these tables:
CREATE TABLE [dbo].[Users]
(
[User_ID] [int] IDENTITY(1,1)PRIMARY KEY NOT NULL ,
[LogIn] [varchar](100) NULL,
[Pass] [varchar](100) NOT NULL,
)
CREATE TABLE [dbo].[Consecutives]
(
[Consecutives_ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[Name] [varchar](100) NULL,
[Value] [int] NOT NULL,
)
I'm being asked to be able to set an edit the User_ID that is going to be used next when adding a new user using the value stated on the Consecutive table.
So if for example the Consecutive value is 50, even if the last user added has the User_ID set to 8 the new user's ID will be 50 and the consecutive updated to 51.
I would do it using a foreign key, but obviously I can't set a primary key to be a foreign key.
I can't find a way to do this.
Can someone help me out?
What you are describing is called a one-to-one relationship.
You create such a relationship by connecting both tables with a foreign key referencing their primary keys (or a unique index).
However, since this is a one-to-one relationship, only the main table actually needs the identity specification on it's primary key.
Your requirement to insert a record to the Users based on an existing record in the Consecutives table seems strange to me. Usually, when you have a one-to-one relationship you populate the related records in both tables in the same transaction.
To create a one-to-one relationship, where Consecutives is the main table, Your DDL should look like this:
CREATE TABLE [dbo].[Consecutives]
(
[Consecutives_ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NULL,
[Value] [int] NOT NULL,
CONSTRAINT PK_Consecutives PRIMARY KEY (Consecutives_ID)
);
CREATE TABLE [dbo].[Users]
(
[User_ID] [int] NOT NULL,
[LogIn] [varchar](100) NULL,
[Pass] [varchar](100) NOT NULL,
CONSTRAINT PK_Users PRIMARY KEY (User_ID),
CONSTRAINT FK_Users_Consecutives FOREIGN KEY (User_ID) REFERENCES [dbo].[Consecutives]([Consecutives_ID])
);
Please note I've removed the identity specification from the User_ID column, and also changed the way the primary key is declared so that I could name it manually.
Naming constraints is best practice since if you ever need to change them it's much simpler when you already know their names.
Now, to insert a single record to both tables in the same transaction you can create a stored procedure like this:
CREATE PROCEDURE InsertUser
(
#Name varchar(100),
#Value int,
#LogIn varchar(100),
#Pass varchar(100)
)
AS
DECLARE #Consecutives AS TABLE
(
Id int
);
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO [dbo].[Consecutives] ([Name], [Value])
OUTPUT Inserted.Consecutives_ID INTO #Consecutives
VALUES (#Name, #Value)
INSERT INTO [dbo].[Users] ([User_ID], [LogIn], [Pass])
SELECT Id, #Login, #Pass
FROM #Consecutives
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLL BACK TRANSACTION
END CATCH
GO
and execute it like this:
EXEC InsertUser 'Zohar Peled', 1, 'Zohar', 'Peled'
You can see a live demo on rextester. (Please note that rextester doesn't allow using transactions so the try...catch and transaction parts are removed from the demo there)
Have you ever tried set identity insert on? This link may help you. To use the identity insert, the user needs some alter table permissions.

SQL Server Temporal Tables - How do I enter a row that isn't "now"?

I'm working on a system that will periodically process messages from an external source and store the result in our database. In particular, it receives messages like "Patient X moved to Location Y at 09:45 AM, 10/22/2018..."
Ideally, I'd like to be able to use SQL Server's Temporal Tables to create a historical trail of "where the patient has been", so that I can query where they were at a specific point in time.
-- ============================================================
CREATE TABLE [dbo].[Patients] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Patients] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[Locations] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Locations] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[PatientLocations] (
[PatientId] [int] NOT NULL,
CONSTRAINT [PK_PatientLocations] PRIMARY KEY([PatientId]),
CONSTRAINT [FK_PatientLocations_PatientId] FOREIGN KEY([PatientId])
REFERENCES [dbo].[Patients] ([Id]),
[LocationId] [int] NOT NULL,
CONSTRAINT [FK_PatientLocations_LocationId] FOREIGN KEY([LocationId])
REFERENCES [dbo].[Locations] ([Id]),
[DateStartedUtc] datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
[DateEndedUtc] datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME ([DateStartedUtc],[DateEndedUtc])
)
WITH ( SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [dbo].[PatientLocations_History] ) );
The problem is that [DateStartedUtc] can only be populated with the current system time, which isn't necessarily the time when the patient's location changed.
My specific question is:
- Is there a good way to input new data into a Temporal Table but tag it with specific start dates? (Does [DateStartedUtc] have to be "GENERATED"?)
- If not, are there other best practices for storing an queryable history table?
Edited to add:
- Aaron reminded me in the comments to mention turning System Versioning OFF and ON again. One potential solution I researched would be to turn System Versioning off, insert a new row into dbo.PatientLocations or dbo.PatientLocations_History, and turn System Versioning back on (all within a transaction). I don't think that's a good solution for regular updates to the table (and it would require me to manually maintain the start and end dates), but I'm open to being convinced.
Additional Updates
To add some more context, my initial solution (before I discovered Temporal Tables) was to maintain a single history table with a trigger:
-- ============================================================
CREATE TABLE [dbo].[Patients] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Patients] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[Locations] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Locations] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[PatientLocations] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_PatientLocations] PRIMARY KEY ([Id]),
[PatientId] [int] NOT NULL,
CONSTRAINT [FK_PatientLocations_PatientId] FOREIGN KEY([PatientId])
REFERENCES [dbo].[Patients] ([Id]),
[LocationId] [int] NOT NULL,
CONSTRAINT [FK_PatientLocations_LocationId] FOREIGN KEY([LocationId])
REFERENCES [dbo].[Locations] ([Id]),
-- Timestamps
[LocationStartedAtDateOffset] [datetimeoffset] NOT NULL,
[_LocationCompletedAtDateOffset] [datetimeoffset] NULL,
);
GO
-- ================================================================================
CREATE TRIGGER [dbo].[TRG_PatientLocations_LocationCompletedAtDateOffset]
ON [dbo].[PatientLocations]
AFTER UPDATE, INSERT, DELETE
AS
BEGIN
WITH
-- ========================================
[ModifiedPatientIds] AS (
SELECT DISTINCT [PatientId]
FROM (
SELECT [PatientId] FROM inserted
UNION SELECT [PatientId] FROM deleted
) p
),
-- ========================================
[PList] AS (
SELECT
p.[Id],
p.[PatientId],
p.[LocationStartedAtDateOffset],
LEAD(p.[LocationStartedAtDateOffset], 1)
OVER(PARTITION BY p.[PatientId] ORDER BY p.[LocationStartedAtDateOffset])
AS [LocationCompletedAtDateOffset]
FROM [dbo].[PatientLocations] p
JOIN [ModifiedPatientIds] mp ON p.[PatientId] = mp.[PatientId]
)
-- ========================================
UPDATE p SET
p.[_LocationCompletedAtDateOffset] = pl.[LocationCompletedAtDateOffset]
FROM [dbo].[PatientLocations] p
JOIN [PList] pl ON p.[Id] = pl.[Id]
END;
GO
I initially moved away from this solution, since triggers generally perform badly.
I thought Temporal Tables would solve my problem elegantly, but as the comments mention, they are really only designed for system versioning, not user-defined versioning.
So my modified question is:
- What is the best way to store and maintain user-defined history in a database?
- Is there a better solution than using triggers? Or is there a more efficient way to use triggers?

How to insert a duplicate value in primary key column?

I have a table that has primary key on first column, but when I see the data available of this table, I find that records are repeated include primary key data. I want to know how can it be possible? Does primary column has repeated data in SQL Server 2008?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[DemoTbl](
[ProcedureId] [int] NOT NULL,
[ProcedureName] [nvarchar](100) NOT NULL,
[VersionNo] [char](5) NULL,
[PublishDate] [datetime] NULL,
[PublishUser] [varchar](50) NULL,
[SpecialtyId] [int] NOT NULL,
[ProcedureNumber] [varchar](20) NULL,
[PowerpointName] [nvarchar](100) NULL,
[Duration] [int] NOT NULL,
[LanguageId] [int] NOT NULL,
[TierId] [smallint] NOT NULL,
[PrintPdf] [bit] NULL,
[PresentationModeId] [tinyint] NULL,
CONSTRAINT [pk_DemoTbl] PRIMARY KEY CLUSTERED
(
[ProcedureId] ASC,
[LanguageId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[DemoTbl] WITH CHECK ADD FOREIGN KEY([PresentationModeId])
REFERENCES [dbo].[DemoTbl] ([PresentationModeId])
GO
ALTER TABLE [dbo].[DemoTbl] WITH CHECK ADD CONSTRAINT [FK_DemoTbl_Specialty] FOREIGN KEY([SpecialtyId])
REFERENCES [dbo].[Specialty] ([SpecialtyId])
GO
ALTER TABLE [dbo].[DemoTbl] CHECK CONSTRAINT [FK_DemoTbl_Specialty]
GO
ALTER TABLE [dbo].[DemoTbl] WITH CHECK ADD CONSTRAINT [FK_DemoTbl_TierMaster] FOREIGN KEY([TierId])
REFERENCES [dbo].[TierMaster] ([TierId])
GO
ALTER TABLE [dbo].[DemoTbl] CHECK CONSTRAINT [FK_DemoTbl_TierMaster]
GO
ALTER TABLE [dbo].[DemoTbl] ADD CONSTRAINT [DF_DemoTbl_CreationDate] DEFAULT (getdate()) FOR [CreationDate]
GO
ALTER TABLE [dbo].[DemoTbl] ADD CONSTRAINT [DF_DemoTbl_ModifiedDate] DEFAULT (getdate()) FOR [ModifiedDate]
GO
ALTER TABLE [dbo].[DemoTbl] ADD CONSTRAINT [DF_DemoTbl_IsActive] DEFAULT ((1)) FOR [IsActive]
GO
ALTER TABLE [dbo].[DemoTbl] ADD CONSTRAINT [DF_DemoTbl_LanguageId] DEFAULT ((1)) FOR [LanguageId]
GO
ALTER TABLE [dbo].[DemoTbl] ADD CONSTRAINT [DF_DemoTbl_ManageContent] DEFAULT ('false') FOR [ManageContent]
GO
ALTER TABLE [dbo].[DemoTbl] ADD CONSTRAINT [DF__Procedure__Print__1B14C01D] DEFAULT ((1)) FOR [PrintPdf]
GO
No, it is not possible in SQL Server to insert records that have duplicate values in the Primary Key.
It is not possible to have more than one row in the same table with the same primary key (PK).
If you are doing a SELECT and getting more than one row with the same PK could be because:
That table actually does not have a PK, maybe it was not properly created. You can check this by doing the following (it should return the PK column(s)):
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'TableName' AND COLUMN_KEY='PRI';
The SELECT statement is not correct. Maybe you are selecting from two or more tables and you are not relating them correctly.
To clarify, you can do the following:
1- Create a new table:
CREATE TABLE IF NOT EXISTS `Customer` (
`id` int(4),
`name` varchar(20),
`surname` varchar(40),
`phone` int(9),
PRIMARY KEY (`id`)
) ENGINE=INNODB;
Now you have a new table for storing customers identified by an ID.
2- Let's add some customers:
INSERT INTO Customer VALUES(111, 'John', 'White', 123456789),
(222, 'Bianca', 'Williams', 987654321),
(333, 'Mikel', 'Peterson', 421345642),
(444, 'Jolene', 'Gomez', 948113552);
3- If you try to insert a customer with an existing PK (id) you will get an error:
INSERT INTO Customer VALUES (222, 'Paul', 'Brown', 123412345);
4- In order to check the final table, you can do the following select:
SELECT * FROM Customer;
No it is not possible to have duplicate primary keys if the primary key constraint has been set to True.
Further to prevent duplicate primary keys set the Identity Specification to True
If this table is an intermediate table in a many to many connection the original columns are foreign keys and able to accept many instances of the same prodId(the whole point of the exercise). If someone then slams a PK on that column then no more duplicates can be added but if you query it the table will still return the original stuff in this guys screenshot.
This scenario can be seen in the Northwind sample database between Products and orders (OrderDetails table has composite PK on OrderID, ProdID but still shows duplicates of both). The PK was added afterwards, after data had been added.
The intermediate table is a link between the Many-to-Many tables and in general doesn't need a PK. Normalization 101.
For PK Constraint it create a Unique Index (Clustered / non Clustered ) on defined PK. If we disable indexes before loading that include PK Unique Index as well than we can insert duplicate PK in the column because the PK constraint is disabled. So while disabling Indexes please avoid PK index not be disable "is_primary_key=0 to disable all other indexes"
Tested -> it's possible if we create a primary key with nonclustered index. If we disable this index we will be able to insert duplicated record then. But - it won't be possible to enable (rebuild) the index back with duplicated values on primary key

Update PK columns in table having clustered keys

I have a database with tables that have clustered primary keys. I believe the term I picked up on is use of a Natural Key. The frontend to the SQL database is programmed to affect changes to all related foreign key tables for the 3,000 selected values which I want to modify. It takes about 13 seconds per change. I have a need to do this in a much shorter timeframe if possible.
The reason for doing this is prep work to migrate to a new CMMS program.
I found reference for use of ON UPDATE CASCADE, but I am not certain this applies.
Among many references, I used the following:
https://social.technet.microsoft.com/Forums/sqlserver/it-IT/23294919-3e6a-4146-a70d-66fa155ed1b3/update-primary-key-column-in-sql-server?forum=transactsql
An example of 2 of the 15 tables having the same named [EQNUM] column follows. Table A is the table that is first modified using the frontend. I left out many columns for each table:
CREATE TABLE A
(
[EQNUM] [varchar](30) NOT NULL,
CONSTRAINT [PK_A] PRIMARY KEY CLUSTERED ([EQNUM] ASC)
)
GO
SET ANSI_PADDING OFF
GO
CREATE TABLE B
(
[EQNUM] [varchar](30) NOT NULL,
[ColA] [varchar](10) NOT NULL,[ColB] [datetime] NOT NULL,
[ColC] [varchar](30) NOT NULL, [ColD] [varchar](30) NOT NULL,
[ColE] [varchar](30) NOT NULL, [ColF] [varchar](30) NOT NULL,
[ColG] [varchar](11) NOT NULL,[ColH] [varchar](10) NOT NULL,
[ColI] [datetime] NOT NULL,[ColJ] [varchar](15) NOT NULL,
[ColK] [int] NULL,
CONSTRAINT [PK_B]
PRIMARY KEY CLUSTERED ([EQNUM] ASC,
[ColA] ASC,[ColB] ASC,[ColC] ASC,[ColD] ASC,[ColE] ASC,
[ColF] ASC,[ColG] ASC,[ColH] ASC,[ColI] ASC,[ColJ] ASC)
)
An example of 1 of 4 sets of UPDATE queries, for which I believe the added first and last ALTER TABLE lines would allow me to affect the update:
ALTER TABLE A NOCHECK CONSTRAINT [PK_EQUIP]
UPDATE A
SET [EQNUM] = REPLACE([EQNUM],'-B','-B0')
WHERE [EQNUM] LIKE '%-A[1-9][0-5][0-9]-%' OR
[EQNUM] LIKE '%-A[1-9][A-F][0-5][0-9]-%' OR
ALTER TABLE A CHECK CONSTRAINT [PK_EQUIP]
ALTER TABLE A NOCHECK CONSTRAINT [PK_B]
UPDATE B
SET [EQNUM] = REPLACE([EQNUM],'-B','-B0')
WHERE [EQNUM] LIKE '%-A[1-9][0-5][0-9]-%' OR
[EQNUM] LIKE '%-A[1-9][A-F][0-5][0-9]-%' OR
ALTER TABLE A CHECK CONSTRAINT [PK_B]
Is it this simple, or am I missing something? Is there a better way?

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