Enabling cascading deletes on either side of a join table - sql-server

I have one User model with a primary key of id. I am currently modeling Supervisor > User relationships with a join table of sorts called user_supervisors which has only two columns, user_id and supervisor_id, both of which are foreign keys referencing the primary key of User record.
Is it possible that when I delete a user (whether they are a supervisor or not), any records containing that user in the user_supervisors table is also deleted?
I have been attempting to make use of sql server's cascading deletes but it doesn't seem to be possible to have cascading deletes on both the user_id and supervisor_id foreign keys at the same time. I always encounter a message along the lines of:
Knex:warning - migration failed with error: CREATE TABLE [user_supervisors] ([user_id] int, [supervisor_id] int, CONSTRAINT [user_supervisors_pkey] PRIMARY KEY ([user_id], [supervisor_id]), CONSTRAINT [user_supervisors_user_id_foreign] FOREIGN KEY ([user_id]) REFERENCES [users] ([id]) ON DELETE CASCADE, CONSTRAINT [user_supervisors_supervisor_id_foreign] FOREIGN KEY ([supervisor_id]) REFERENCES [users] ([id]) ON DELETE CASCADE) - Could not create constraint or index. See previous errors.
For the record I am using knex to run my database migrations
Below is the SQL used when creating each table mentioned above:
CREATE TABLE [users]
(
[id] int identity(1,1) not null primary key
, [created_at] datetime
, [updated_at] datetime
, [email] nvarchar(255) not null
, [first_name] nvarchar(255)
, [last_name] nvarchar(255)
, [password] nvarchar(255) not null
, [company_id] int
, CONSTRAINT [users_email_unique] UNIQUE ([email])
, CONSTRAINT [users_company_id_foreign] FOREIGN KEY ([company_id]) REFERENCES [companies] ([id]) ON DELETE CASCADE
)
CREATE TABLE [user_supervisors]
(
[user_id] int
, [supervisor_id] int
, CONSTRAINT [user_supervisors_pkey] PRIMARY KEY ([user_id], [supervisor_id])
, CONSTRAINT [user_supervisors_user_id_foreign] FOREIGN KEY ([user_id]) REFERENCES [users] ([id]) ON DELETE CASCADE
, CONSTRAINT [user_supervisors_supervisor_id_foreign] FOREIGN KEY ([supervisor_id]) REFERENCES [users] ([id])
)

Related

SQL Server foreign key with several cascading paths

I have three tables in SQL Server 2014.
First one is a Product table (productid, ...)
Second one contains ProductVersions of that product (ProductVersionID, ProductID, ...)
Third one contains licenses for the products (LicenseID, ProductID)
These tables have foreign keys on the product ID with on delete cascade.
Now I want to add another table mapping the licenses to specific ProductVersions. This can be a n:m relationship, so I create an mapping table LicenseVersion (LicenseID, ProductVersionID)
When I try to add an foreign key to that relations I get an error saying can't add foreign key because there are loops or serveral cascading paths. Use on delete no action or change the foreign key.
I think, I get why this happens (deleting the product will cause the LicenseVersion row to be deleted from both ways in one transaction) but what is the best practice to solve this?
The database should be consistent anytime, so I don't want to solve this in the software application logic.
I could use a trigger (I think) and an foreign key with no action, but is this the best way?
CREATE TABLE [dbo].[Products]
(
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_dbo.Products]
PRIMARY KEY CLUSTERED([ProductID] ASC)
)
CREATE TABLE [dbo].[ProductVersions]
(
[ProductVersionID] [int] IDENTITY(1,1) NOT NULL,
[ProductID] [int] NOT NULL,
[Name] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_dbo.ProductVersions]
PRIMARY KEY CLUSTERED ([ProductVersionID] ASC)
)
CREATE TABLE [dbo].[License]
(
[LicenseId] [int] IDENTITY(1,1) NOT NULL,
[LicenseName] [nvarchar](255) NOT NULL,
[ProductId] [int] NOT NULL,
CONSTRAINT [PK_dbo.License]
PRIMARY KEY CLUSTERED ([LicenseId] ASC)
)
CREATE NONCLUSTERED INDEX [IX_ProductId]
ON [dbo].[License] ([ProductId] ASC)
CREATE NONCLUSTERED INDEX [IX_ProductID]
ON [dbo].[ProductVersions] ([ProductID] ASC)
ALTER TABLE [dbo].[License] WITH CHECK
ADD CONSTRAINT [FK_dbo.License_dbo.Products_ProductId]
FOREIGN KEY([ProductId]) REFERENCES [dbo].[Products] ([ProductID])
ON UPDATE CASCADE
ON DELETE CASCADE
ALTER TABLE [dbo].[License] CHECK CONSTRAINT [FK_dbo.License_dbo.Products_ProductId]
ALTER TABLE [dbo].[ProductVersions] WITH CHECK
ADD CONSTRAINT [FK_dbo.ProductVersions_dbo.Products_ProductID]
FOREIGN KEY([ProductID]) REFERENCES [dbo].[Products] ([ProductID])
ON UPDATE CASCADE
ON DELETE CASCADE
ALTER TABLE [dbo].[ProductVersions] CHECK CONSTRAINT [FK_dbo.ProductVersions_dbo.Products_ProductID]
--add new table
CREATE TABLE [dbo].[LicenseVersion]
(
[LicenseID] [int] NOT NULL,
[ProductVersionID] [int] NOT NULL,
CONSTRAINT [PK_LicenseVersion]
PRIMARY KEY CLUSTERED ([LicenseID] ASC, [ProductVersionID] ASC)
)
ALTER TABLE [dbo].[LicenseVersion] WITH CHECK
ADD CONSTRAINT [FK_LicenseVersion_ProductVersions]
FOREIGN KEY([ProductVersionID]) REFERENCES [dbo].[ProductVersions] ([ProductVersionID])
ON UPDATE CASCADE
ON DELETE CASCADE
ALTER TABLE [dbo].[LicenseVersion] CHECK CONSTRAINT [FK_LicenseVersion_ProductVersions]
--error here:
ALTER TABLE [dbo].[LicenseVersion] WITH CHECK
ADD CONSTRAINT [FK_LicenseVersion_Licenses]
FOREIGN KEY([LicenseID]) REFERENCES [dbo].[License] ([LicenseID])
ON UPDATE CASCADE
ON DELETE CASCADE
ALTER TABLE [dbo].[LicenseVersion] CHECK CONSTRAINT [FK_LicenseVersion_Licenses]

SQL Server Foreign Key references invalid Table 'employees'

I try to run this SQL Server query:
USE DB_UBB;
CREATE TABLE dept_emp (
emp_no INT NOT NULL,
dept_no CHAR(4) NOT NULL,
from_date DATE NOT NULL,
to_date DATE NOT NULL,
FOREIGN KEY (emp_no) REFERENCES employees(emp_no) ON DELETE CASCADE, -- Error here
FOREIGN KEY (dept_no) REFERENCES departments(dept_no) ON DELETE CASCADE, -- And here
PRIMARY KEY (emp_no, dept_no)
);
CREATE INDEX (emp_no);
CREATE INDEX (dept_no);
and I get these errors:
Foreign key 'FK__dept_emp__8bc6840bee39d6cef4bd' references invalid table 'employees'.
Foreign key 'fk__dept_emp__99bc0b2304d3f32059a9' references invalid table 'departments'.
even though I have these tables:
What do I do wrong?
EDIT:
Added Whole DB:
SQL ‘hides’ the columns from the Key of the Clustered Index in Nonclustered Indexes.
You have created a composite primary on both emp_no,dept_no
cluster index of primary will hide both columns from indexes in following queries and will generate error
CREATE INDEX (emp_no);
CREATE INDEX (dept_no);
If you are specifying the foreign key after the column specifications, try using the CONSTRAINT clause instead:
to_date DATE NOT NULL,
CONSTRAINT fk_dept_emp_dept FOREIGN KEY (emp_no) REFERENCES employees(emp_no) ON DELETE CASCADE,
CONSTRAINT fk_dept_emp_emp FOREIGN KEY (dept_no) REFERENCES departments(dept_no) ON DELETE CASCADE,
Aparently, I even though the tables were created, it didn't recognize them.
I added an <if not exist, create tables>
I also removed the CREATE INDEX (emp_no); and CREATE INDEX (dept_no); as #Muhammad Nasir said, but it didn't fix the referencing issue.
Solution:
USE DB_UBB;
IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE name='employees' and xtype='U')
CREATE TABLE employees (
emp_no INT NOT NULL,
birth_date DATE NOT NULL,
first_name VARCHAR(14) NOT NULL,
last_name VARCHAR(16) NOT NULL,
gender VARCHAR(1) NOT NULL CHECK (gender IN('M', 'F')),
hire_date DATE NOT NULL,
PRIMARY KEY (emp_no)
);
GO
IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE name='departments' and xtype='U')
CREATE TABLE departments (
dept_no CHAR(4) NOT NULL,
dept_name VARCHAR(40) NOT NULL,
PRIMARY KEY (dept_no),
UNIQUE (dept_name)
);
GO
IF NOT EXISTS (SELECT * FROM SYSOBJECTS WHERE name='dept_emp' and xtype='U')
CREATE TABLE dept_emp (
emp_no INT NOT NULL,
dept_no CHAR(4) NOT NULL,
from_date DATE NOT NULL,
to_date DATE NOT NULL,
FOREIGN KEY (emp_no) REFERENCES employees(emp_no) ON DELETE CASCADE,
FOREIGN KEY (dept_no) REFERENCES departments(dept_no) ON DELETE CASCADE,
PRIMARY KEY (emp_no, dept_no)
);
GO

Is it possible to implement self referencing foreign key with update cascade in SQL Server?

I've this table:
CREATE TABLE [SomeTable](
[Id] int NOT NULL
,[SomeColumn] varchar(50) NULL
,[ParentId] int NULL CONSTRAINT [PK_SomeTable] PRIMARY KEY CLUSTERED ([Id] ASC)
ALTER TABLE [SomeTable] WITH CHECK ADD CONSTRAINT
[FK_SomeTable_SomeTable] FOREIGN KEY([ParentId])
REFERENCES [SomeTable] ([Id])
ALTER TABLE [SomeTable] CHECK CONSTRAINT [FK_SomeTable_SomeTable]
Sql Server does not allow me to put ON UPDATE CASCADE.
Is there any way to get that if i update Id column, all child rows ParentId get updated too?

Foreign Key error SQL Server

I have three tables that are to be connected using a foreign key.
CREATE TABLE customer
(
customerID INT,
lastname VARCHAR(70) NOT NULL,
firstname VARCHAR(70) NOT NULL,
phone VARCHAR(10) CONSTRAINT phoneCheck CHECK ((phone LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')),
category VARCHAR(1) NOT NULL CONSTRAINT categoryDefault DEFAULT 'A',
CONSTRAINT categoryCheck CHECK (category IN ('A', 'B', 'C')),
CONSTRAINT customerPK
PRIMARY KEY (customerID)
)
CREATE TABLE booking
(
customerID INT,
packageCode VARCHAR(6) UNIQUE,
bookingDate DATE NOT NULL DEFAULT GETDATE(),
amountPaid MONEY CONSTRAINT amountPaidDefault DEFAULT 0.00,
CONSTRAINT bookingPK
PRIMARY KEY (customerID),
CONSTRAINT bookingFK
FOREIGN KEY (customerID)
REFERENCES customer (customerID)
ON DELETE CASCADE
);
CREATE TABLE package
(
packageCode VARCHAR(6),
destination VARCHAR(70),
CONSTRAINT packageCodeCheck CHECK (packageCode LIKE ('YFK%')),
price MONEY NOT NULL CONSTRAINT priceCheck CHECK ((price BETWEEN 1000 AND 10000)),
passportRequired VARCHAR(1) NOT NULL CONSTRAINT passportRequiredDefault DEFAULT 'Y',
CONSTRAINT passportCheck CHECK (passportRequired IN ('Y', 'N')),
CONSTRAINT packagePK
PRIMARY KEY (packageCode),
CONSTRAINT packageFK
FOREIGN KEY (packageCode)
REFERENCES booking (packageCode)
ON DELETE CASCADE
)
I got the Foreign key between customer and booking set properly, its purpose is to delete all associated bookings with that customer. I am currently trying to do the same between package and bookings, When a package record is deleted, it should also delete the corresponding records. I continue to get the error
The INSERT statement conflicted with the FOREIGN KEY constraint
"packageFK". The conflict occurred in database "travel", table
"dbo.booking", column 'packageCode'.
Im not quite sure what this is referencing as I have encountered this error before and fixed it, unfortunately... I cannot in this case.
All help is greatly appreciated.
Thanks,
Bryan
Since you want to delete all booking rows when a package is deleted, the package table must be the primary table and the booking table must reference the package table. Remove the foreign key constraint from the table and add the following to the bookings table:
CONSTRAINT booking_packageFK
FOREIGN KEY (packageCode)
REFERENCES package (packageCode)
ON DELETE CASCADE
You should also remove the UNIQUE constraint from the packageCode on the booking table.
I don't think you have your foreign key relationship set up correctly even between Customer and Booking.
In your Create Table customer following tells the server that CustomerId is the Primary Key in customer table:
CONSTRAINT customerPK
PRIMARY KEY (customerID)
In your Create Table booking following tells the server that CustomerId is the Primary Key as well as a Foreign Key that references customer:
CONSTRAINT bookingPK
PRIMARY KEY (customerID),
CONSTRAINT bookingFK
FOREIGN KEY (customerID)
REFERENCES customer (customerID)
ON DELETE CASCADE
Similarly in your package table you have set packageCode as both primary and foreign key.
What I think you need is:
CustomerId in Customer table should be the primary key
There should be a BookingId and a CustomerId in the Booking table. BookingId will be the primary key and CustomerId will be the foreign key that references Customer.
There should be a BookingId in the Package table. It will be a foreign key that references Booking.

multiple constraint keys

if i have tabled:
Resource (id (PK), name)
Manager (id(PK), resource_id (FK), manager_resource_ID(FK))
Should resource_id and manager_id both be foreign keys into the Resource table.
i obviously dont want to enter any values in each of those columns that are not proper resources
when i add the first relationship (resource_id <-> id) it works fine but
when i add the second one (manager_resource_id <-> id) it fails with the error:
Unable to create relationship [ . . .] The ALTER TABLE statement conflicted with the FOREIGN KEY constraint [... ]. The conflict occured in table Resource, column id
or do i need to break this out into 3 tables?
Resource(id, first, last)
Resource_manager(id, resource_id, manager_ID)
Manager(id)
Just a hint:
UPDATE:
If your model has employee-manager as many-to-many (bit unusual) then you could do:
CREATE TABLE Employee
(
EmployeeID int NOT NULL
,[Name] varchar(50)
)
go
ALTER TABLE Employee ADD
CONSTRAINT PK_Employee PRIMARY KEY CLUSTERED (EmployeeID ASC)
go
CREATE TABLE Manager
(
EmployeeID int NOT NULL
,ManagerID int NOT NULL
)
go
ALTER TABLE Manager ADD
CONSTRAINT PK_Manager PRIMARY KEY CLUSTERED (EmployeeID ASC, ManagerID ASC)
,CONSTRAINT FK1_Manager FOREIGN KEY (EmployeeID) REFERENCES Employee(EmployeeID)
,CONSTRAINT FK2_Manager FOREIGN KEY (ManagerID) REFERENCES Employee(EmployeeID)
,CONSTRAINT chk_Manager CHECK (EmployeeID <> ManagerID)
go
You have to create the foreign keys in the Manager table.

Resources