Reputation: 291
I really need to know if there is any way I can change or delete the primary key constraint of a table to UNIQUE constraint
When I try to drop the primary constraint from the Entreprise
table:
ALTER TABLE Entreprise
DROP CONSTRAINT PK__Entrepri__AABA1D8F1B0907CE
I get this error :
Msg 3725, Level 16, State 0, Line 1
The constraint 'PK_Entrepri_AABA1D8F1B0907CE' is being referenced by table 'Dossier', foreign key constraint 'Cle_FDOs'.
Msg 3727, Level 16, State 0, Line 1
Could not drop constraint. See previous errors.
So the problem is I don't want to delete the rows in the dossier
table
This is the Entreprise
table :
create table Entreprise
(
ID_Entreprise integer ,
Raison_Social varchar(100),/*Nom Entreprise*/
Num_Raison_Sociale varchar(20) unique ,
Adress varchar(100),
Abreviation varchar(10),
CNSS_Entreprise integer unique,
Eligible varchar(20),/*AUTOMATIQUE par raport aux CNSS_Entreprise*/
Effectif integer,/*NB SALARIE*/
Ville varchar(20),
Responsable varchar(20),
EMAIL_Responsable varchar(20),
Tel_Responsable varchar(20),
Fax_Responsable varchar(20),
Directeur varchar(20),
EMAIL_Directeur varchar(20),
Tel_Directeur varchar(20),
Fax_Directeur varchar(20),
RIB varchar(60),/*ici non sur le dossier lo*/
Nom_Giac varchar(50) foreign key references GIAC(Nom_Giac),
primary key(Nom_Giac,ID_Entreprise)
)
GO
and this is the Dossier
table:
create table Dossier
(
ID_Dossier integer primary key,
ID_Entreprise int,/*AUTOMATIQE par rapotrt aux la cnss de l'entreprise qui l'a donne*/
Date_Depot datetime ,
Type_Etude varchar(2),/*DS IF combobox*/
Dernier_Type varchar(2),/* AUTOMATIQUE */
Eligibile varchar(3),/* par raport aux Dernier Type et CNSS et COTISTAION EXERCICES */
Fiche_Information varchar(3),/*checkbox o/n */
Buletin_Adhesion varchar(3),
Fiche_Renseignment varchar(3),
Attestation varchar(3),
Date_Debut datetime,
Date_Fin datetime,
--Etat_Dossier varchar(3), /* hado m7aydine mn war9a*/
--Motif text,/*en cas de rejet, peu prendre null apart le cnss et cotisation ex et dernier formation *//* hado m7aydine mn war9a*/
ID_Cabinet integer foreign key references Cabinet(ID_Cabinet),
Montant_Demander decimal(6,2),
Duree integer,
Porcentage_Taux varchar(3), /* combobox 70% 80% */
Nom_Giac varchar(50),
constraint Cle_FDOs foreign key(Nom_Giac,ID_Entreprise) references Entreprise(Nom_Giac,ID_Entreprise),
)
GO
Upvotes: 3
Views: 3893
Reputation: 12803
I ran into this problem several times and ending up making a stored proc that can take any primary key constraint and turn into unique index. It drops and recreates anything referencing the table in question, (which is the tricky part for highly referenced tables).
It can handle multi-part primary keys.
CREATE PROCEDURE spPrimaryKeyToUniqueKey
@schema VARCHAR(255),
@tableName VARCHAR(255)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @constraintsToDrop NVARCHAR(MAX) = '';
DECLARE @constraintsToCreate NVARCHAR(MAX) = '';
DECLARE @indexesToDrop NVARCHAR(MAX) = '';
DECLARE @indexesToCreate NVARCHAR(MAX) = '';
;WITH _fks AS (
SELECT
FkName = fk.[name]
, SchemaName = sch.[name]
, TableName = tab1.[name]
, ColumnName = col1.[name]
, ReferencedSchema = sch2.[name]
, ReferencedTableName = tab2.[name]
, ReferencedColumnName = col2.[name]
, ReferencedColOrder = ic.key_ordinal
FROM sys.foreign_key_columns fkc
JOIN sys.foreign_keys fk ON fk.object_id = fkc.constraint_object_id
JOIN sys.tables tab1 ON tab1.object_id = fkc.parent_object_id
JOIN sys.schemas sch ON tab1.schema_id = sch.schema_id
JOIN sys.columns col1 ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
JOIN sys.tables tab2 ON tab2.object_id = fkc.referenced_object_id
JOIN sys.schemas sch2 ON sch2.schema_id = tab2.schema_id
JOIN sys.columns col2 ON col2.column_id = fkc.referenced_column_id AND col2.object_id = tab2.object_id
JOIN sys.indexes i ON fk.key_index_id = i.index_id AND i.object_id = tab2.object_id
JOIN sys.index_columns ic ON col2.column_id = ic.column_id AND ic.object_id = tab2.object_id AND i.index_id = ic.index_id
)
, _fksWithColList AS (
SELECT
f.FkName
, f.SchemaName
, f.TableName
, f.ReferencedSchema
, f.ReferencedTableName
, TableColNameList = STUFF(
(SELECT ',[' + ff.ColumnName + ']'
FROM _fks ff
WHERE f.FkName = ff.FkName AND f.SchemaName = ff.SchemaName AND f.TableName = ff.TableName AND f.ReferencedSchema = ff.ReferencedSchema AND f.ReferencedTableName = ff.ReferencedTableName
ORDER BY ff.ReferencedColOrder
FOR XML PATH('')), 1, 1, '')
, ReferencedTableColNameList = STUFF(
(SELECT ',[' + ff.ReferencedColumnName + ']'
FROM _fks ff
WHERE f.FkName = ff.FkName AND f.SchemaName = ff.SchemaName AND f.TableName = ff.TableName AND f.ReferencedSchema = ff.ReferencedSchema AND f.ReferencedTableName = ff.ReferencedTableName
ORDER BY ff.ReferencedColOrder
FOR XML PATH('')), 1, 1, '')
FROM _fks f
GROUP BY f.FkName, f.SchemaName, f.TableName, f.ReferencedSchema, f.ReferencedTableName
)
, _commands AS (
SELECT *,
DropStatement = REPLACE(REPLACE(REPLACE('ALTER TABLE [{0}].[{1}] DROP CONSTRAINT IF EXISTS [{2}];',
'{0}', SchemaName),
'{1}', TableName),
'{2}', FkName),
CreateStatement = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE('ALTER TABLE [{0}].[{1}] DROP CONSTRAINT IF EXISTS [{2}]; ALTER TABLE [{0}].[{1}] ADD CONSTRAINT [{2}] FOREIGN KEY ({3}) REFERENCES [{4}].[{5}]({6});',
'{0}', SchemaName),
'{1}', TableName),
'{2}', FkName),
'{3}', TableColNameList),
'{4}', ReferencedSchema),
'{5}', ReferencedTableName),
'{6}', ReferencedTableColNameList)
FROM _fksWithColList
WHERE ReferencedSchema = @schema AND ReferencedTableName = @tableName
)
SELECT @constraintsToDrop = @constraintsToDrop + DropStatement + CHAR(13)+CHAR(10), @constraintsToCreate = @constraintsToCreate + c.CreateStatement + CHAR(13)+CHAR(10)
FROM _commands c
;WITH _indexes AS (
SELECT
TableName = t.[name]
, SchemaName = s.[name]
, IndexName = i.[name]
, ColumnName = c.[name]
, ColOrder = ic.key_ordinal
, ColDesc = ic.is_descending_key
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
JOIN sys.indexes i ON t.object_id = i.object_id
JOIN sys.columns c ON t.object_id = c.object_id
JOIN sys.index_columns ic ON t.object_id = ic.object_id AND c.column_id = ic.column_id AND i.index_id = ic.index_id
WHERE s.[name] = @schema AND t.[name] = @tableName AND i.is_primary_key = 1
)
, indexesWithColList AS (
SELECT
TableName
, SchemaName
, IndexName
, IndexColList = STUFF(
(SELECT ',[' + ii.ColumnName + ']' + IIF(ii.ColDesc = 1, ' DESC', '')
FROM _indexes ii
WHERE i.TableName = ii.TableName AND i.SchemaName = ii.SchemaName AND i.IndexName = ii.IndexName AND ii.ColOrder > 0
ORDER BY ii.ColOrder
FOR XML PATH('')), 1, 1, '')
, IndexColNameList = STUFF(
(SELECT '_' + ii.ColumnName
FROM _indexes ii
WHERE i.TableName = ii.TableName AND i.SchemaName = ii.SchemaName AND i.IndexName = ii.IndexName AND ii.ColOrder > 0
ORDER BY ii.ColOrder
FOR XML PATH('')), 1, 1, '')
FROM _indexes i
GROUP BY i.TableName, i.SchemaName, i.IndexName
)
, _commands AS (
SELECT *,
DropStatement = REPLACE(REPLACE(REPLACE('ALTER TABLE [{0}].[{1}] DROP CONSTRAINT {2};',
'{0}', i.SchemaName),
'{1}', i.TableName),
'{2}', i.IndexName),
CreateStatement = REPLACE(REPLACE(REPLACE(REPLACE('CREATE UNIQUE NONCLUSTERED INDEX [{0}] ON [{1}].[{2}] ({3});',
'{0}', 'UX_' + i.SchemaName + '_' + i.TableName + '_' + i.IndexColNameList),
'{1}', i.SchemaName),
'{2}', i.TableName),
'{3}', i.IndexColList)
FROM indexesWithColList i
)
SELECT @indexesToDrop = @indexesToDrop + c.DropStatement + CHAR(13)+CHAR(10), @indexesToCreate = @indexesToCreate + c.CreateStatement + CHAR(13)+CHAR(10)
FROM _commands c
DECLARE @sql NVARCHAR(MAX);
SET @sql = REPLACE(REPLACE(REPLACE(REPLACE('
SET XACT_ABORT ON;
BEGIN TRAN t1
--Drop foreign keys
{0}
--Drop indexes
{1}
--Create indexes
{2}
--Recreate foreign keys
{3}
COMMIT TRAN t1
',
'{0}', @constraintsToDrop),
'{1}', @indexesToDrop),
'{2}', @indexesToCreate),
'{3}', @constraintsToCreate);
PRINT @sql;
EXEC sp_executesql @sql
END
GO
Upvotes: 1
Reputation: 2405
You cannot do the "change" automatically, with a single SQL instruction, but you can achieve that if you want to.
First, you need to drop the foreign-keys of those tables containing references to the referenced table, Enterprise
, in your concrete case.
You need to drop the foreign-key from Dossier
, then drop the primary-key from Enterprise
, and create a UNIQUE
constraint.
Another question would be, why are you interested on doing that?
Maybe you can read this other SO thread discussing about the matter.
Upvotes: 2
Reputation: 13056
As the error is suggesting, you need to delete the foreign-key reference first. This will not delete the records in Dossier
(see my SQL Fiddle example.) :
ALTER TABLE Dossier DROP CONSTRAINT Cle_FDOs;
Upvotes: 1