Drop and add constraints in one stored procedure - sql-server

I would like to drop a primary key and then add a primary key to the same column in 1 stored procedure.
I have the drop constraints within Begin Transaction' andCommit Transactionthen try to add the constraints within another set ofBegin TransactionandCommit Transaction`.
I am getting the error that a primary key already exists for this column when it was dropped in the first set of transactions.
This is the code:
BEGIN TRANSACTION
ALTER TABLE [dbo].[Lens] DROP CONSTRAINT [FK_Lens_Style];
ALTER TABLE [dbo].[Lens] DROP CONSTRAINT [FK_Lens_Type];
ALTER TABLE [dbo].[Coating] DROP CONSTRAINT [PK_Coatings];
ALTER TABLE [dbo].[CoatingCost] DROP CONSTRAINT [PK_CoatingCost];
COMMIT TRANSACTION
BEGIN TRANSACTION
ALTER TABLE [dbo].[Coating]
ADD CONSTRAINT [PK_dbo.Coating]
PRIMARY KEY CLUSTERED ([CoatingId] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
COMMIT TRANSACTION
If the first set of constraints are dropped and committed, shouldn't I be able to add a primary key on the column that previously had a primary key?
UPDATE
I think I know the problem. It is because there is a Foreign Key associated with the primary key that I am trying to drop.
I will need to drop all of the foreign keys associated with all of the primary keys that I am trying to drop. Then add the primary keys back. Then add the foreign keys back.

Are you sure that the problem is not with the same index name existing in the database in the moment when your code tries to create one? The name of an index must be unique in the entire database scope not only in a single table scope.
You might want to diagnose it by putting a below query before, between and after your transaction operations:
SELECT
so.name AS tableName
, si.name AS indexName
, si.type_desc AS indexType
, si.is_primary_key AS isPK
FROM
sys.indexes AS si
JOIN sys.objects AS so ON si.object_id = so.object_id
WHERE
si.name IS NOT NULL /*otherwise it will select all tables without explicit index*/
AND
so.type = 'U'/*otherwise it unnecessarily will select indexes of system tables*/

Related

Why does a newly-inserted row show up in two filegroups on a partitioned table in SQL Server?

I partitioned an existing table by year. After inserting a new record for a date in 2020, the new record shows as part of the 2020 partition and in the primary filegroup. I'm having a hard time finding if that's what is supposed to happen, or if I have something configured incorrectly.
This is what the partitions look like after inserting the record. Before inserting the record, this query showed 3 records in the primary filegroup, and 3 records in the 2021 group.
I was expecting a new row in the 2020 partition and for the number of rows in the primary filegroup to remain at 3, but perhaps those are wrong expectations.
Does the primary filegroup always show the total of the partitions, or should rows only show up as being in just the partition in which they belong?
I can show how I set this all up, and I'd be happy to, but this question is more about what the results should look like. I don't want the same row in multiple partitions.
Edit
I just found this link. It shows the results of inserting data where new rows only show up in the correct partition and not also in primary. So it appears I've done something incorrectly.
https://www.sqlshack.com/how-to-automate-table-partitioning-in-sql-server/
Edit 2
The reason primary has all 4 rows may be that its upper boundary is null. Since primary already existed on the table, that was never modified. Perhaps I need to modify it?
Edit 3
Interesting that this link also shows the sum of the partitions within the primary.
https://www.mssqltips.com/sqlservertip/2888/how-to-partition-an-existing-sql-server-table/
Script that SSMS generated for partitioning
USE [Sandbox]
GO
BEGIN TRANSACTION
CREATE PARTITION FUNCTION [PunchPF1](datetimeoffset(7)) AS RANGE LEFT FOR VALUES (N'2020-01-01T00:00:00-05:00', N'2021-01-01T00:00:00-05:00', N'2022-01-01T00:00:00-05:00')
CREATE PARTITION SCHEME [PunchPS1] AS PARTITION [PunchPF1] TO ([Pre2020_Punch], [2020_Punch], [2021_Punch], [2022_Punch])
ALTER TABLE [time].[Punch] DROP CONSTRAINT [PK_Punch] WITH ( ONLINE = OFF )
ALTER TABLE [time].[Punch] ADD CONSTRAINT [PK_Punch] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE CLUSTERED INDEX [ClusteredIndex_on_PunchPS1_637515095430656187] ON [time].[Punch]
(
[PunchTime]
)WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PunchPS1]([PunchTime])
DROP INDEX [ClusteredIndex_on_PunchPS1_637515095430656187] ON [time].[Punch]
COMMIT TRANSACTION
Edit 4
Here is the same query, but with IndexName and IndexID included.
Edit 5
Things look better now after doing this:
USE [Sandbox]
--------------------------------------------------------------------------------------------------------------------
-- Drop table, scheme, and function
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'Punch' AND TABLE_SCHEMA = 'time')
DROP TABLE time.Punch;
IF EXISTS (SELECT 1 FROM sys.partition_schemes WHERE name = 'PunchPS1')
DROP PARTITION SCHEME PunchPS1
IF EXISTS (SELECT 1 FROM sys.partition_functions WHERE name = 'PunchPF1')
DROP partition function PunchPF1
--------------------------------------------------------------------------------------------------------------------
-- Files and Filegroups
-- Add files and filegroups manually in SSMS because each SQL Server could have different file locations?
-- How to add a file and filegroup using SQL:
-- https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-file-and-filegroup-options?view=sql-server-ver15
-- To see an example of creating filegroups in SQL, script the Sandbox DB AS CREATE...
--------------------------------------------------------------------------------------------------------------------
-- Partition Function
CREATE PARTITION FUNCTION [PunchPF1](datetimeoffset(7))
AS RANGE RIGHT FOR VALUES (N'2020-01-01T00:00:00-05:00', N'2021-01-01T00:00:00-05:00', N'2022-01-01T00:00:00-05:00')
--------------------------------------------------------------------------------------------------------------------
-- Partition Scheme
CREATE PARTITION SCHEME [PunchPS1]
AS PARTITION [PunchPF1] TO ([Pre2020_Punch], [2020_Punch], [2021_Punch], [2022_Punch])
--------------------------------------------------------------------------------------------------------------------
-- Table
CREATE TABLE [time].[Punch](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[EmployeeId] [bigint] NOT NULL,
[PunchTime] [datetimeoffset](7) NOT NULL
) ON [PunchPS1] (PunchTime)
--------------------------------------------------------------------------------------------------------------------
-- Add some data
INSERT INTO [time].[Punch] ([EmployeeId],[PunchTime]) VALUES (10,'2020-12-18 16:40:20')
INSERT INTO [time].[Punch] ([EmployeeId],[PunchTime]) VALUES (10,'2020-12-20 16:40:20')
INSERT INTO [time].[Punch] ([EmployeeId],[PunchTime]) VALUES (10,'2020-12-22 16:40:20')
INSERT INTO [time].[Punch] ([EmployeeId],[PunchTime]) VALUES (10,'2021-3-18 16:40:20')
As seen here, the boundaries look good, I'm using RANGE RIGHT, and the rows seem to show in the correct partition.
The only question I have now is if it's bad to have no clustered index?

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.

A flexible foreign key

I have a sql server database. I'm developing a vb.net application.
Now I'm thinking to have an "Event" table that should keep all the events related with my database. But one of the fields of this table should be a field ObjectID that is related with the record that this event has to do. But this record may be on different tables. For example :
Event 1 ---- Record 25 on table Clients
Event 2 ---- Record 30 Table Invoices
Event 3 ---- Record 40 Table Articles
...
The problem is that this field ObjectID should be a Foreign key in a flexible way , because may be related with different tables.
Is there any way I can resolve this case ?
Thank you !
One way to solve it would be to add a table to your database to act like a base for the other tables and connet it with a one to one relationship to the other tables, and then connect the events table to this base table.
This will allow you to keep data integrity for each of the tables.
The base table can be as simple as just one column, or can have columns thay all other tables have in common, thus implementing a sort of "inheritance" in your data structure.
Create the base table (assuming no common columns between other tables):
CREATE TABLE TblObjectBase
(
ObjectBase_Id int IDENTITY(1,1) PRIMARY KEY
)
Then, for any other table that needs to be referenced by the ObjectId in the Events table:
CREATE TABLE TblClients
(
Client_Id int PRIMARY KEY,
Client_FirstName varchar(10),
Client_LastName varchar(10),
-- Other client related data
CONSTRAINT FK_TblClients_TblObjectBase
FOREIGN KEY(Client_Id)
REFERENCES TblObjectBase(ObjectBase_Id)
)
CREATE TABLE TblInvoices
(
Invoice_Id int PRIMARY KEY,
-- other incoice related data
CONSTRAINT FK_TblInvoices_TblObjectBase
FOREIGN KEY(Invoice_Id)
REFERENCES TblObjectBase(ObjectBase_Id)
)
The only thing remaining is to insert a new value to the TblObjectBase for any insert on your other tables. This can be be easily achived by either stored procedures or instead of insert triggers.
An insert procedure could look like this:
CREATE PROCEDURE Insert_TblClients
(
#Client_FirstName varchar(10),
#Client_LastName varchar(10),
-- any other client related data you might have
)
AS
DECLARE #ClientId int
-- Insert a new record to the base table:
INSERT INTO TblObjectBase DEFAULT VALUES;
-- Get the id you've just inserted:
SELECT #ClientId = SCOPE_IDENTITY();
-- Insert the data to the clients table:
INSERT INTO TblClients
(Client_Id, Client_FirstName, Client_LastName.....) VALUES
(#ClientId, #Client_FirstName, #Client_LastName...)
An instead of insert trigger would look like this:
CREATE TRIGGER TblClients_IO_Insert ON TblClients INSTEAD OF INSERT
AS
BEGIN
DECLARE #ClientId int
-- Insert a new record to the base table:
INSERT INTO TblObjectBase DEFAULT VALUES;
-- Get the id you've just inserted:
SELECT #ClientId = SCOPE_IDENTITY();
INSERT INTO TblClients
(Client_Id, Client_FirstName, Client_LastName.....)
SELECT #ClientId, Client_FirstName, Client_LastName.....
FROM inserted
END
If you choose to go with the instead of insert, the fact that the Identity value comes from another table should be transparent to the client (your vb.net program).
SQL Server doesn't support creating such constraint.
But you can simulate the link programmatically without much trouble.
CREATE TABLE tbl_Event
(
[idEvent] INT IDENTITY(1,1) NOT NULL,
[TableSource] INT NOT NULL,
[SourceId] INT NOT NULL
--Events fields
CONSTRAINT [PK_Tests] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
In the above exemple, SourceId is the foreign key
TableSource is used to know which table the foreign key is from.
In table source you could use sys.objects.object_id of the table.
However, since you don't have much control on those keys that are managed by SQL, I recommend using you own table with defined constant for each table instead of sys.objects.
This way you also have more control on which table can have foreign key in this table and it become really handy overtime.
CREATE TABLE tbl_tableSource(
[idTableSource] INT IDENTITY(1,1) NOT NULL,
[Constant] INT NOT NULL,
[Name] NVARCHAR(255) NULL
CONSTRAINT [PK_Tests] PRIMARY KEY CLUSTERED
(
[idTableSource] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO tbl_tableSource
VALUES(1000, 'tbl_SomeTable')
INSERT INTO tbl_tableSource
VALUES(2000, 'tbl_SomeOtherTable')
Also, this kind of relation, is less good for performance then standard one. So the field type of your keys and of the constant is really important. It should not be heavy. This because you will need to create an index on tbl_event.
To simulate cascade delete ON, you need to implement trigger on parent table like this :
CREATE TRIGGER OneParentTableOnDelete ON tbl_SomeTable
FOR DELETE
AS
BEGIN
DELETE tbl_Event
FROM DELETED
INNER JOIN tbl_Event ON tbl_Event.TableSource = [Constant for tbl_SomeTable]
AND tbl_Event.idSource = DELETED.id --PrimaryKey
END
To retrieve data, you can then do like this
--For events about one foreign key
SELECT *
FROM tbl_event
WHERE tbl_Event.TableSource = [Constant for tbl_SomeTable]
AND tbl_Event.idSource = #idPrimareyKeyOfSomeTable
--Fore events about multiple foreign key
SELECT *
FROM [tbl_SomeTable]
INNER JOIN tbl_event ON tbl_Event.TableSource = [Constant for tbl_SomeTable]
AND tbl_Event.idSource = [tbl_SomeTable].id --PrimaryKey
You could create an 'INDEXED VIEW' -- define it however you like to pull the objectIDs + any other relevant fields, as you've described, from record 25 of the clients table, record record 30 of the invoices table, and so on.
You could do the same thing with a stored procedure.
Depending on how you intend to consume the data -- if you're just pulling it into a vb.net datatable, either of these options should work fine.
A benefit to an approach like this is that you don't have to create or maintain any new tables in your database.

SQL Server 2008: What to set FK as PK?

I'm putting together my own database and from examples I've seen, Foriegn Key can also be set as Primary Keys.
I was creating my Tables so that all of my FK were also PK. Is this wrong? When should a FK be a PK? Does it have to be a PK?
Primary Key's make sense in their own table... as the Id and Identity. But when using the Id is another table, does it have to be a PK as well?
A Foreign Key should only be the Primary Key when your trying to create a 1 to 1 or 1 to zero/1 mapping.
Example:
I have a Person table, an Employee table, and a Contractor table. All Employees are people, all Contractors are people and every Person is either an employee or a Contractor
Essentially you would end up with something like this.
In response to your people have multiple addresses you should create an association table. Here is a diagram.
As you can see now every person can have many addresses and since each Employee is a person then every Employee can have many addresses. This is the same for Contractor as well.
Edited: Here is the Change Script from SQL Server
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Address
(
AddressId bigint NOT NULL,
Address nvarchar(50) NULL,
City nvarchar(50) NULL,
State nvarchar(50) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Address ADD CONSTRAINT
PK_Address PRIMARY KEY CLUSTERED
(
AddressId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE dbo.Address SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Person
(
PersonId bigint NOT NULL,
Name nvarchar(50) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Person ADD CONSTRAINT
PK_Person PRIMARY KEY CLUSTERED
(
PersonId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE dbo.Person SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.PersonAddress
(
PersonId bigint NOT NULL,
AddressId bigint NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.PersonAddress ADD CONSTRAINT
PK_PersonAddress PRIMARY KEY CLUSTERED
(
PersonId,
AddressId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE dbo.PersonAddress ADD CONSTRAINT
FK_PersonAddress_Person FOREIGN KEY
(
PersonId
) REFERENCES dbo.Person
(
PersonId
) ON UPDATE NO ACTION
ON DELETE NO ACTION
GO
ALTER TABLE dbo.PersonAddress ADD CONSTRAINT
FK_PersonAddress_Address FOREIGN KEY
(
AddressId
) REFERENCES dbo.Address
(
AddressId
) ON UPDATE NO ACTION
ON DELETE NO ACTION
GO
ALTER TABLE dbo.PersonAddress SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Employee
(
EmployeeId bigint NOT NULL,
EmployeeNumber nvarchar(50) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT
PK_Employee PRIMARY KEY CLUSTERED
(
EmployeeId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT
FK_Employee_Person FOREIGN KEY
(
EmployeeId
) REFERENCES dbo.Person
(
PersonId
) ON UPDATE NO ACTION
ON DELETE NO ACTION
GO
ALTER TABLE dbo.Employee SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Contractor
(
ContractorId bigint NOT NULL,
ContractorNumber nvarchar(50) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Contractor ADD CONSTRAINT
PK_Contractor PRIMARY KEY CLUSTERED
(
ContractorId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE dbo.Contractor ADD CONSTRAINT
FK_Contractor_Person FOREIGN KEY
(
ContractorId
) REFERENCES dbo.Person
(
PersonId
) ON UPDATE NO ACTION
ON DELETE NO ACTION
GO
ALTER TABLE dbo.Contractor SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
There is only one scenarios that would require a FK to also be a PK.
When the table represents a subclass, or subset, of the things in the PK table, for example, Eg, SalariedEmployees table which has a FK to the Employees table...
A FK is a field pointing to the PK of another table. That's it.
A table linked to itself could contain a FK pointing to its own PK.
A PK that is also a FK can only happen in the child table of a 1 to 1 relationship.
An FK should only also be a PK if the two tables have a one-to-one relationship and the second table was added because the first was too wide and these were items not always needed in most queries.
It will not work at all if you have a one-to-many relationship or a many-to-many relationship.
FKs are much more often not also the PK. If I havea person table and a related address table, If I make the PK and the FK the same thing, then I can only store one address, but most address tables allow for mulitple addresses for the same person or organization. IN that case you would have and AddressID as the PK and a person_id as the FK to the person table. This is the most common PK/FK scenario.
One situation where a given column is both a PK and an FK is the relational model for the gen-spec design pattern. In one of the other responses "Employees" is a specialization of Persons". The PK in the employees tables references the PK in the Persons table. So the PK in the specialized table is also an FK.
This allows the creation of a view that joins employees and persons to provide in a single view all the data about employees, whether that data is peculiar to employees (like "Hire Date") or is common to all persons, whether or not they are employees (like "Date of Birth").
It is not good practice to make every PK also be an FK. The FKs should reflect the logical structure of the data. If the logical model is illogical, you're headed for trouble.

How to cascade rename PK on table, MS SQL 2005

I have successfully been able to rename a table and drop all constraints on that table with foreign key relationships and build they all back up. However, now I am at a point where the PK_tblFoo exists in more than one place (when I transfer the table to another DB). Renaming the table does not rename the primary key.
How would I cascade rename the primary key? I have renamed the table, I just need to get this portion figured out.
I believe I will need to this manually, drop all FK constraints, run this guy:
IF EXISTS ( SELECT *
FROM sys.indexes
WHERE object_id = OBJECT_ID(N'[dbo].[tblFoo]')
AND name = N'PK_tblBusinessListings' )
ALTER TABLE [dbo].[tblFoo] DROP CONSTRAINT [PK_tblBusinessListings]
GO
ALTER TABLE [dbo].[tblFoo]
ADD CONSTRAINT [PK_tblFoo_1] PRIMARY KEY CLUSTERED ( [ListingID] ASC )
WITH ( PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF,
ONLINE = OFF ) ON [PRIMARY]
Then go through and set up all the FK constraint with the new PK name....errrgh....this is going to take a while.
You could also use a refactoring tool, I know Visual Studio Team Edition for Database Professionals could handle this.

Resources