resolving foreign constraints among connected tables - sql-server

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 ....

Related

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.

Difference between 'Foreign Key Relations' window and 'Keys' in Object explorer SSMS

In the image, the Foreign Key Relationships window is showing the FK for the itemModifier_Rel table while on the object explorer it doesn't shows the same results.
What are the differences between these?
I'm having a problem of duplicated keys, some DBA have a wrong process that causes this and I'm trying to fix it.
I deleted the duplicates but now I'm seeing this. Although the resulting CREATE TABLE script for the table shows just 3 FK while on the Foreign Key Relationships I'm seeing 6
Here's the table's script after dropping the duplicated FK
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[itemModifier_Rel](
[ItemModifierTypeID] [bigint] NOT NULL,
[ItemID] [bigint] NOT NULL,
[ModifierItemID] [bigint] NULL,
[ModifierSequenceID] [bigint] NULL,
PRIMARY KEY NONCLUSTERED
(
[ItemModifierTypeID] ASC,
[ItemID] 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
ALTER TABLE [dbo].[itemModifier_Rel] WITH CHECK ADD FOREIGN KEY([ItemID])
REFERENCES [dbo].[item] ([ItemID])
GO
ALTER TABLE [dbo].[itemModifier_Rel] WITH CHECK ADD FOREIGN KEY([ItemModifierTypeID])
REFERENCES [dbo].[itemModifierType_Cat] ([ItemModifierTypeID])
GO
ALTER TABLE [dbo].[itemModifier_Rel] WITH CHECK ADD FOREIGN KEY([ModifierItemID])
REFERENCES [dbo].[item] ([ItemID])
GO
On left you see the keys constraint names under Keys. On right you have the dialog for setting up key properties visually. That dialog is listing all the foreign keys of your table plus all the foreign keys that reference to table. IOW you have 3 FK + 2 references to your table PK in that picture.

How do you deal with foreign keys, unique indexes and default constraints when using a shadow table copy and rename?

I have a large table in a MSSQL 2008 database, to which I need to add a new column, set a value on that new column and then make it not null.
Because the table is large, it keeps timing out on our deployment process. I read that I can use a shadow table and SELECT INTO.., then use sp_rename to replace the original table. As per this answer: https://stackoverflow.com/a/19141346/119624
The table has lots of foreign keys, indexes and constraints. I'm slightly confused as to how I should deal with those.
I assume that the process is as below. But I would appreciate it if someone could confirm whether I'm doing this in the optimum way.
Imagine this is my current table:
CREATE TABLE [dbo].[MyTable](
[MyTableId] [int] IDENTITY(1,1) NOT NULL,
[SomeFkId] [int] NOT NULL,
[IsLocked] [bit] NOT NULL CONSTRAINT [DF_MyTable_IsLocked] DEFAULT ((0)),
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED
(
[MyTableId] 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].[MyTable] WITH CHECK
ADD CONSTRAINT [FK_MyTable_SomeFk] FOREIGN KEY([SomeFkId])
REFERENCES [dbo].[SomeFk] ([SomeFkId])
GO
ALTER TABLE [dbo].[MyTable] CHECK CONSTRAINT [FK_MyTable_SomeFk]
GO
I now want to add a new shadow table. Do I need to create the table with the defaults and constraints like so?
CREATE TABLE [dbo].[MyTableShadow](
[MyTableId] [int] IDENTITY(1,1) NOT NULL,
[SomeFkId] [int] NOT NULL,
[SomeColumn] [int] NOT NULL,
[IsLocked] [bit] NOT NULL CONSTRAINT [DF_MyTableShadow_IsLocked] DEFAULT ((0)),
[NewColumn] [int] NOT NULL,
CONSTRAINT [PK_MyTableShadow] PRIMARY KEY CLUSTERED
(
[MyTableId] 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].[MyTableShadow] WITH CHECK
ADD CONSTRAINT [FK_MyTableShadow_SomeFk] FOREIGN KEY([SomeFkId])
REFERENCES [dbo].[SomeFk] ([SomeFkId])
GO
ALTER TABLE [dbo].[MyTableShadow] CHECK CONSTRAINT [FK_MyTableShadow_SomeFk]
GO
Then do the SELECT INTO...
SELECT MyTable.*, MyTable.SomeColumn -- copying value
INTO MyTableShandow
FROM MyTable
Then do the rename:
EXEC sp_rename 'MyTable', 'MyTableOld'
EXEC sp_rename 'MyTableShadow', 'MyTable'
Then do the drop:
DROP TABLE MyTableOld
Then rename the constraints and foreign keys:
EXEC sp_rename 'PK_MyTableShadow', 'PK_MyTable', 'object' -- PK
EXEC sp_rename 'FK_MyTableShadow_SomeFk', 'FK_MyTable_SomeFk', 'object' -- FK
EXEC sp_rename 'DF_MyTableShadow_IsLocked', 'DF_MyTable_IsLocked', 'object' -- DF
Is that the correct process, or is there another easier way? (I have a table that has a lot of FKs and constraints, so I'm trying to reduce the pain!

Convert INT to BIGINT in SQL Server

SQL 2005, 600,000,000 rows.
I have a table called Location currently using the data type INT in identity PK column LocationID. I would like to attempt converting this data type to BIGINT.
The following script I think should help to allow inserted into the PK column but i am unsure how to progress form here.
SET IDENTITY_INSERT LOCATION ON /*allows insert into the identity column*/`
SET IDENTITY_INSERT LOCATION OFF /*Returns the identity column to initial state*/`
Location table create script below:
CREATE TABLE [dbo].[Location](
[LocationID] [int] IDENTITY(1,1) NOT NULL,
[JourneyID] [int] NULL,
[DeviceID] [int] NOT NULL,
[PacketTypeID] [int] NULL,
[PacketStatusID] [int] NULL,
CONSTRAINT [Location_PK] PRIMARY KEY CLUSTERED
(
[LocationID] 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
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [Device_Location_FK1] FOREIGN KEY([DeviceID])
REFERENCES [dbo].[Device] ([DeviceID])
GO
ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [Device_Location_FK1]
GO
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [PacketStatus_Location_FK1] FOREIGN KEY([PacketStatusID])
REFERENCES [dbo].[PacketStatus] ([PacketStatusID])
GO
ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [PacketStatus_Location_FK1]
GO
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [PacketType_Location_FK1] FOREIGN KEY([PacketTypeID])
REFERENCES [dbo].[PacketType] ([PacketTypeID])
GO
ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [PacketType_Location_FK1]
One option i think would be to copy the data to a new table then delete the old table and rename the new one however we have constraints that will need to be dropped for this to work.
Your idea of a new table is the way to go.
On a development server, you can see the script that SSMS would produce if you change the data type using the table designer. It is a good start. This will add triggers and constraints back afterwards.
A tool like Red gate SQL Compare also allows you to check that everything was created OK

SQL Alter: add multiple FKs?

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]

Resources