views:

169

answers:

3

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
+2  A: 

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;
Steve Kass
I always use the designer, and it actually works pretty well. It also much faster for most cases.
Kevin
thanks steve. added sample sql code.
pencilslate
@Kevin: "Faster for most cases" than what? The designer generates SQL and/or stored proc calls that anyone could write (but often shouldn't). How can the designer's SQL and proc calls be faster than a developer's SQL and proc calls?
Steve Kass
@pencilslate: It's a one-liner. If the table contains any data, you must supply defaults for the new columns, because they are NOT NULL. I've picked the numbers 640 and 480, just to show where they go.ALTER TABLE dbo.TableA ADD PhotoWidth INT NOT NULL DEFAULT 640, PhotoHeight INT NOT NULL DEFAULT 480;
Steve Kass
@steve: it worked. thanks! Also, can you suggest SQL design and data editing tools other SSMS?
pencilslate
@pencilslate: SSMS is fine if you stick with the query editor and do your design and editing by executing SQL statements. You can get started with the designers for single tables without recently-added features, then work from the scripts SSMS can generate for you. It doesn't take long to learn to script tables, indexes, and constraints from scratch using SQL CREATE statements.
Steve Kass
A: 
tpdi
Thanks! Is reading closely worth an up vote? :)
Steve Kass
+1  A: 

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'
Kevin
the NOCHECK constraint didn't work. i have added the sample sql to my post.
pencilslate
For the record, if you execute NOCHECK, then CHECK as you suggest, the check and foreign key constraints will not be rechecked on the table data, and they will remain "untrusted" and not usable by the optimizer.If you want to recheck the data, you must say CHECK CHECK, believe it or not!ALTER TABLE [name] CHECK CHECK CONSTRAINT ALL
Steve Kass
NOCHECK for some reason still doesn't allow me to alter the table. sounds like, its simpler to execute the alter statement for columns separately than dropping and creating table. again, i believe i need to drop and create if the columns being modified have constraints associated with it. appreciate the explanation. thanks!
pencilslate