简体   繁体   English

使用 SQL Server 2008 删除或将主键约束更改为 UNIQUE 约束

[英]Delete or change the primary key constraint to UNIQUE constraint using SQL Server 2008

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我真的需要知道是否有任何方法可以将表的主键约束更改或删除为 UNIQUE 约束

When I try to drop the primary constraint from the Entreprise table:当我尝试从Entreprise表中删除主要约束时:

ALTER TABLE Entreprise
DROP CONSTRAINT  PK__Entrepri__AABA1D8F1B0907CE

I get this error :我收到此错误:

Msg 3725, Level 16, State 0, Line 1消息 3725,级别 16,状态 0,第 1 行
The constraint 'PK_ Entrepri _AABA1D8F1B0907CE' is being referenced by table 'Dossier', foreign key constraint 'Cle_FDOs'.约束“PK_ Entrepri _AABA1D8F1B0907CE”是由表“档案”,外键约束“Cle_FDOs”引用。
Msg 3727, Level 16, State 0, Line 1消息 3727,级别 16,状态 0,第 1 行
Could not drop constraint.无法删除约束。 See previous errors.请参阅以前的错误。

So the problem is I don't want to delete the rows in the dossier table所以问题是我不想删除dossier表中的行

This is the Entreprise table :这是Entreprise表:

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:这是Dossier表:

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

You cannot do the "change" automatically, with a single SQL instruction, but you can achieve that if you want to.您无法通过一条 SQL 指令自动进行“更改”,但如果您愿意,可以实现这一点。

First, you need to drop the foreign-keys of those tables containing references to the referenced table, Enterprise , in your concrete case.首先,在您的具体情况下,您需要删除包含对被引用表Enterprise的引用的那些表的外键。

You need to drop the foreign-key from Dossier , then drop the primary-key from Enterprise , and create a UNIQUE constraint.您需要从Dossier删除外键,然后从Enterprise删除主键,并创建一个UNIQUE约束。

Another question would be, why are you interested on doing that?另一个问题是,你为什么对这样做感兴趣?

Maybe you can read this other SO thread discussing about the matter.也许您可以阅读讨论此事的其他 SO 线程

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 .) :不会删除Dossier的记录(请参阅我的 SQL Fiddle示例。):

ALTER TABLE Dossier DROP CONSTRAINT Cle_FDOs;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM