SQL Alter: add multiple FKs? - sql-server

From here
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(SID);
How do I add several keys with SQL Server? Is it something like the below? (I cant test ATM and unfortunately I have no way to test queries unless I run it through code)
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(SID),
ADD FOREIGN KEY (customer_sid2) REFERENCES CUSTOMER(SID2);
or is it like
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid, customer_sid2) REFERENCES CUSTOMER(SID, SID2)

The second code block from your question:
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(SID),
ADD FOREIGN KEY (customer_sid2) REFERENCES CUSTOMER(SID2);
will take care of what you are trying to do.

ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(SID),
FOREIGN KEY (customer_sid2) REFERENCES CUSTOMER(SID2),
FOREIGN KEY (customer_sid3) REFERENCES CUSTOMER(SID3);

Here is the sql generated by sqlserver after I use the database diagram to draw the foreign key. Their approach is that one alter table for one foreign key
USE [TimeSheet]
GO
/****** Object: Table [dbo].[WeekTasks] Script Date: 05/19/2010 20:09:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[WeekTasks](
[ID] [int] IDENTITY(1,1) NOT NULL,
[WeekID] [int] NOT NULL,
[TaskDescription] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[ProjectID] [int] NOT NULL
CONSTRAINT [PK_WeekTasks] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[WeekTasks] WITH CHECK ADD CONSTRAINT [FK_WeekTasks_Projects] FOREIGN KEY([ProjectID])
REFERENCES [dbo].[Projects] ([ID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[WeekTasks] CHECK CONSTRAINT [FK_WeekTasks_Projects]
GO
ALTER TABLE [dbo].[WeekTasks] WITH CHECK ADD CONSTRAINT [FK_WeekTasks_WeekTimeSheet] FOREIGN KEY([WeekID])
REFERENCES [dbo].[WeekTimeSheet] ([ID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[WeekTasks] CHECK CONSTRAINT [FK_WeekTasks_WeekTimeSheet]

Related

Bare Sql Server - Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths

This is very similar to Introducing Foreign key Constraint on table may cause cycles or multiple cascade paths, except that the answer to that question does not explain the rationale behind the error.
I have the following simple schema:
CREATE TABLE [dbo].[DbInfo](
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY
)
GO
CREATE TABLE [dbo].[MyTable](
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[DbInfo1Id] [int] NOT NULL,
[DbInfo2Id] [int] NOT NULL
)
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [FK_MyTable_DbInfo_DbInfo1Id] FOREIGN KEY([DbInfo1Id])
REFERENCES [dbo].[DbInfo] ([Id])
ON DELETE CASCADE
GO
Now I would like to add the same constraint to the column MyTable.DbInfo2Id:
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [FK_MyTable_DbInfo_DbInfo2Id] FOREIGN KEY ([DbInfo2Id])
REFERENCES [DbInfo] ([Id])
ON DELETE CASCADE;
But I get the following error:
Introducing FOREIGN KEY constraint 'FK_MyTable_DbInfo_DbInfo2Id' on table 'MyTable' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
You can reproduce it in the Sql Fiddle
Why what I am doing here is problematic?
Because the CASCDE mode will drop ID that can possibly be use by the other constraints that will cause cascade too that will drop ID that can possibly be use by the primer constraints that will cause cascade too... an so on !

ALTER COLUMN datatype to NOT NULL without dropping index and manually recreating it

I have a table with foreign key:
CREATE TABLE [dbo].[MyTable](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ForeignId] [int] NULL)
ALTER TABLE [dbo].[MyTable] WITH CHECK ADD CONSTRAINT [FK_MyTable_OtherTable] FOREIGN KEY([ForeignId])
REFERENCES [dbo].[OtherTable] ([ID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[ExpedíciaVýrobky] CHECK CONSTRAINT [FK_MyTable_OtherTable]
I would like to alter the ForeignId datatype to NOT NULL:
ALTER TABLE [dbo].[MyTable] ALTER COLUMN ForeignId INT NOT NULL;
This requires to drop the FK contraint and recreate it.
Is it possible to do so without manually scripting ALTER TABLE CHECK ADD CONSTRAINT ... FOREIGN KEY bla bla with all the details?
For example, if somebody edited the ON DELETE meanwhile, I don't wont to override this change.
EDIT:
In ideal world, I would like to have stored procedure SpAlterColumnToNotNULL(tablename, columnname), that would do the dropping and recreating indexes automatically.

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]

How can Reference Foreign key to Multiple tables?

I am trying to create a BOM structure i have 6 product tables which contains different attributes and a BOMHEADER and BOMDETAIL tables. Before creating the BOM structure i like to Validate or check the existence of the bomitem in either of the six tables. So i tried to creating BOMHEADER field as shown below using multiple constraints, but i get the following error message
"The INSERT Statement conflicted with the FOREIGN KEY constraint
What is the best way to resolve the issue.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[BOMHEAD](
[bomItem] [int] NOT NULL,
[bomRev] [nvarchar](6) NOT NULL,
[rollup] [bit] NULL,
CONSTRAINT [PK_BOMHEAD_KEY_0] PRIMARY KEY CLUSTERED
(
[bomItem] ASC,
[bomRev] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[BOMHEAD] WITH CHECK ADD FOREIGN KEY([bomItem])
REFERENCES [dbo].[parts] ([itemId])
GO
ALTER TABLE [dbo].[BOMHEAD] WITH CHECK ADD FOREIGN KEY([bomItem])
REFERENCES [dbo].[Tires] ([titemId])
GO
ALTER TABLE [dbo].[BOMHEAD] WITH CHECK ADD FOREIGN KEY([bomItem])
REFERENCES [dbo].[Discs] ([itemId])
GO
ALTER TABLE [dbo].[BOMHEAD] WITH CHECK ADD FOREIGN KEY([bomItem])
REFERENCES [dbo].[Rims] ([itemId])
GO
ALTER TABLE [dbo].[BOMHEAD] WITH CHECK ADD FOREIGN KEY([bomItem])
REFERENCES [dbo].[Wheel] ([wheelItemId])
GO
ALTER TABLE [dbo].[BOMHEAD] WITH CHECK ADD FOREIGN KEY([bomItem])
REFERENCES [dbo].[Assemblies] ([itemId])
GO
The structure you post is not check that bomItem is exists in any of that given table but it is required that bomItem must exists in ALL TABLES.
You should do it the other way round by making BOMHEAD to primary key table and set fk of other table to refer pk on BOMHEAD.
This way it will guarantee that every other part table will have BOMHEAD.
The way you did is to guarantee that BOMHEAD will have every other parts.
But if you insist that bomItem need to check for existence in either of the six tables(maybe to prevent unwanted reference from other table?),You can't use fk what you need is check constrain with user defined function or create association table which maintain the relation between BOMHEAD and others.
You should have general table with BOMs that are referenced via Foreign Key by all these tables.

resolving foreign constraints among connected tables

I have two tables A and B with A referencing a column in B with foreign key constraint. Now, i am trying to add more columns and constraints to table A by dropping table A and creating the table A again with new columns. SQL Server Mgmt Studio provides the "Drop and Create" option to do this where i alter the create table statement to add more columns.
Executing the statements throws an error stating A is referenced by a foreign key constraint. To fix this, i had to removed the foreign key constraint from the table A and then execute "drop and create" the statement. In my case, i could do this by dropping one constraint. I can't image doing the same with a set of tables cross referencing each other.
This should be a common occurrence for most of the SQL designers and i am wondering if there is a way to manage this situation without deleting and recreating the web of constraints across tables.
Appreciate your comments!
EXAMPLE OF SQL:
Current table:
CREATE TABLE [dbo].[TableA](
[PhotoId] [bigint] IDENTITY(1,1) NOT NULL,
[PhotoTypeId] [bigint] NOT NULL,
[PhotoDescription] [nvarchar](max) NULL,
[LastModifiedBy] [bigint] NOT NULL,
[LastModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED
(
[PhotoId] 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].[TableA] WITH NOCHECK ADD CONSTRAINT [FK_TableA_TableAType] FOREIGN KEY([PhotoTypeId])
REFERENCES [dbo].[TableAType] ([PhotoTypeId])
GO
ALTER TABLE [dbo].[TableA] NOCHECK CONSTRAINT [FK_TableA_TableAType]
GO
ALTER TABLE [dbo].[TableA] WITH NOCHECK ADD CONSTRAINT [FK_TableA_TableB1] FOREIGN KEY([LastModifiedBy])
REFERENCES [dbo].[TableB] ([UserId])
GO
ALTER TABLE [dbo].[TableA] NOCHECK CONSTRAINT [FK_TableA_TableB1]
GO
ALTER TABLE [dbo].[TableA] ADD CONSTRAINT [DF_TableA_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
GO
expected table
CREATE TABLE [dbo].[TableA](
[PhotoId] [bigint] IDENTITY(1,1) NOT NULL,
[PhotoTypeId] [bigint] NOT NULL,
[PhotoDescription] [nvarchar](max) NULL,
***[PhotoWidth] [int] NOT NULL,
[PhotoHeight] [int] NOT NULL,***
[LastModifiedBy] [bigint] NOT NULL,
[LastModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED
(
[PhotoId] 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].[TableA] WITH NOCHECK ADD CONSTRAINT [FK_TableA_TableAType] FOREIGN KEY([PhotoTypeId])
REFERENCES [dbo].[TableAType] ([PhotoTypeId])
GO
ALTER TABLE [dbo].[TableA] NOCHECK CONSTRAINT [FK_TableA_TableAType]
GO
ALTER TABLE [dbo].[TableA] WITH NOCHECK ADD CONSTRAINT [FK_TableA_TableB1] FOREIGN KEY([LastModifiedBy])
REFERENCES [dbo].[TableB] ([UserId])
GO
ALTER TABLE [dbo].[TableA] NOCHECK CONSTRAINT [FK_TableA_TableB1]
GO
ALTER TABLE [dbo].[TableA] ADD CONSTRAINT [DF_TableA_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
GO
Solution: Don't use the table designer in Management Studio. Seriously. Don't. It's a relic from more than a decade ago, and it doesn't know SQL very well. (Check out connect.microsoft.com, and you'll find many, many bugs and suggestions filed against it.)
You can (and should) add columns and constraints using SQL without dropping and recreating the table, copying data, recreating constraints, etc.
ALTER TABLE A ADD myNewColumn int;
ALTER TABLE A ADD CONSTRAINT ...
If you have a particular situation you don't know the SQL for, please give the CREATE TABLE/INDEX/CONSTRAINT statements and explain what you need to do.
Added: For the example you added to your question, here's the one line SQL. I added defaults just because you'll need them if your table already contains data when you add the columns, which are NOT NULL.
ALTER TABLE dbo.TableA ADD PhotoWidth INT NOT NULL DEFAULT 640, PhotoHeight INT NOT NULL DEFAULT 480;
I've never run into this problem. When I modify a table, I use the Designer to add the columns, save, and it works like magic... It warns me about other tables referencing this one, but I press "OK", and my table is modified !
Anyway, you can remove the reference constraints on the tables by doing:
ALTER TABLE [name] NOCHECK CONSTRAINT ALL
and enable them with:
ALTER TABLE [name] CHECK CONSTRAINT ALL
If you are modifying a lot of tables, you can do:
Before modifications:
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
After modifications:
EXEC sp_msforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
No, you have to drop the constrainsts. But the Good News!™ is that you can use a select from the information_schema tables (or your rdbms' equivalent) to generate the alter table drop constraint statements.
Ah, but Steve Kass read your question more closely than I did. Just add the columns, without dropping the table, with alter table add column ....

Resources