web-dev-qa-db-fra.com

Supprimer l'identité d'une colonne dans une table

Nous avons une table de 5 Go (près de 500 millions de lignes) et nous voulons supprimer la propriété d'identité de l'une des colonnes, mais lorsque nous essayons de le faire via SSMS, le délai expire.

Cela peut-il être réalisé via T-SQL?

91
Conrad Jagger

Vous ne pouvez pas supprimer une spécification IDENTITY une fois définie.

Pour supprimer la colonne entière:

ALTER TABLE yourTable
DROP COLUMN yourCOlumn;

Informations sur ALTER TABLE ici

Si vous devez conserver les données tout en supprimant la colonne IDENTITY, vous devrez:

  • Créer une nouvelle colonne
  • Transférez les données de la colonne IDENTITY existante vers la nouvelle colonne
  • Supprimez la colonne IDENTITY existante.
  • Renommez la nouvelle colonne avec le nom de colonne d'origine
112
Adam Wenger

Si vous voulez faire ceci sans ajouter et remplir une nouvelle colonne , sans réorganiser les colonnes et sans temps mort car aucune donnée ne change sur la table, faisons de la magie avec fonctionnalité de partitionnement (mais aucune partition n'étant utilisée, vous n'avez pas besoin de l'édition Enterprise):

  1. Supprimer toutes les clés étrangères qui pointent vers cette table
  2. Scriptez la table à créer; renommer tout, par exemple 'MyTable2', 'MyIndex2', etc . Supprimez la spécification IDENTITY.
  3. Vous devriez maintenant avoir deux tables "identiques", l'une pleine, l'autre vide sans IDENTITÉ.
  4. Exécuter ALTER TABLE [Original] SWITCH TO [Original2]
  5. Maintenant, votre table d'origine sera vide et la nouvelle aura les données. Vous avez changé les métadonnées pour les deux tables (instantané). 
  6. Supprimez l'original (table maintenant vide), exec sys.sp_rename pour renommer les différents objets de schéma en noms d'origine, puis vous pourrez recréer vos clés étrangères.

Par exemple, étant donné:

CREATE TABLE Original
(
  Id INT IDENTITY PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value ON Original (Value);

INSERT INTO Original
SELECT 'abcd'
UNION ALL 
SELECT 'defg';

Vous pouvez faire ce qui suit:

--create new table with no IDENTITY
CREATE TABLE Original2
(
  Id INT PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value2 ON Original2 (Value);

--data before switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

ALTER TABLE Original SWITCH TO Original2;

--data after switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

--clean up
DROP TABLE Original;
EXEC sys.sp_rename 'Original2.IX_Original_Value2', 'IX_Original_Value', 'INDEX';
EXEC sys.sp_rename 'Original2', 'Original', 'OBJECT';


UPDATE Original
SET Id = Id + 1;

SELECT *
FROM Original;
63
Mark Sowul

Cela est compliqué par les contraintes de clé étrangère et primaire, voici donc quelques scripts pour vous aider dans votre cheminement:

Commencez par créer une colonne en double avec un nom temporaire:

alter table yourTable add tempId int NOT NULL default -1;
update yourTable set tempId = id;

Ensuite, obtenez le nom de votre contrainte de clé primaire:

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'yourTable';

Maintenant, essayez de supprimer la contrainte de clé primaire pour votre colonne:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;

Si vous avez des clés étrangères, cela échouera. Si c'est le cas, supprimez les contraintes de clé étrangère. CONSERVEZ LA PISTE QUI VOUS TENEZ EN CHARGE POUR SO POUVOIR AJOUTER LES CONTRAINTES PLUS TARD !!!

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'otherTable';
alter table otherTable drop constraint fk_otherTable_yourTable;
commit;
..

Une fois que toutes vos contraintes de clé étrangère ont été supprimées, vous pouvez supprimer la contrainte PK, supprimer cette colonne, renommer votre colonne temporaire et ajouter la contrainte PK à cette colonne:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;
alter table yourTable drop column id;
EXEC sp_rename 'yourTable.tempId', 'id', 'COLUMN';
ALTER TABLE yourTable ADD CONSTRAINT PK_yourTable_id PRIMARY KEY (id) 
commit;

Enfin, ajoutez les contraintes FK dans:

alter table otherTable add constraint fk_otherTable_yourTable foreign key (yourTable_id) references yourTable(id);
..

El Fin!

56
Briguy37

Je viens d'avoir ce même problème. 4 déclarations dans SSMS au lieu d’utiliser l’interface graphique et c’était très rapide.

  • Faire une nouvelle colonne

    alter table users add newusernum int;

  • Copier les valeurs sur

    update users set newusernum=usernum;

  • Déposer l'ancienne colonne

    alter table users drop column usernum;

  • Renommez la nouvelle colonne à l'ancien nom de colonne

    EXEC sp_RENAME 'users.newusernum' , 'usernum', 'COLUMN';

15
liberty_

Le script suivant supprime le champ Identité pour une colonne nommée 'Id'

J'espère que ça aide.

BEGIN TRAN
BEGIN TRY
    EXEC sp_rename '[SomeTable].[Id]', 'OldId';

    ALTER TABLE [SomeTable] ADD Id int NULL

    EXEC ('UPDATE [SomeTable] SET Id = OldId')

    ALTER TABLE [SomeTable] NOCHECK CONSTRAINT ALL

    ALTER TABLE [SomeTable] DROP CONSTRAINT [PK_constraintName];
    ALTER TABLE [SomeTable] DROP COLUMN OldId
    ALTER TABLE [SomeTable] ALTER COLUMN [Id] INTEGER NOT NULL
    ALTER TABLE [SomeTable] ADD CONSTRAINT PK_JobInfo PRIMARY KEY (Id)

    ALTER TABLE [SomeTable] CHECK CONSTRAINT ALL

    COMMIT TRAN
END TRY
BEGIN CATCH
    ROLLBACK TRAN   
    SELECT ERROR_MESSAGE ()
END CATCH
9
bluedot

Le code ci-dessous fonctionne aussi bien, lorsque nous ne connaissons pas le nom de la colonne d'identité.

et souhaitez copier des données dans une nouvelle table temporaire telle que Invoice_DELETED. et la prochaine fois que nous utilisons: insérer dans Invoice_DELETED, sélectionnez * depuis Invoice où ...

SELECT t1.*
INTO Invoice_DELETED
FROM Invoice t1
LEFT JOIN Invoice ON 1 = 0
--WHERE t1.InvoiceID = @InvoiceID

merci spécial à 'Andriy M'

pour plus d'explications, voir: https://dba.stackexchange.com/a/138345/101038

3
Zolfaghari
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'

Cependant, le code ci-dessus ne fonctionne que si aucune relation clé primaire-étrangère

1
Jekin Kalariya

J'avais les mêmes exigences, et vous pouvez essayer de cette façon, ce que je vous recommande personnellement, s'il vous plaît, concevez manuellement votre table et votre script, et ce que j'ai fait ci-dessous a été de renommer l'ancien nom de table et de limiter la sauvegarde.

=============================

            /* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
            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
            ALTER TABLE dbo.SI_Provider_Profile
                DROP CONSTRAINT DF_SI_Provider_Profile_SIdtDateTimeStamp
            GO
            ALTER TABLE dbo.SI_Provider_Profile
                DROP CONSTRAINT DF_SI_Provider_Profile_SIbHotelPreLoaded
            GO
            CREATE TABLE dbo.Tmp_SI_Provider_Profile
                (
                SI_lProvider_Profile_ID int NOT NULL,
                SI_lSerko_Integrator_Token_ID int NOT NULL,
                SI_sSerko_Integrator_Provider varchar(50) NOT NULL,
                SI_sSerko_Integrator_Profile varchar(50) NOT NULL,
                SI_dtDate_Time_Stamp datetime NOT NULL,
                SI_lProvider_ID int NULL,
                SI_sDisplay_Name varchar(10) NULL,
                SI_lPurchased_From int NULL,
                SI_sProvider_UniqueID varchar(255) NULL,
                SI_bHotel_Pre_Loaded bit NOT NULL,
                SI_sSiteName varchar(255) NULL
                )  ON [PRIMARY]
            GO
            ALTER TABLE dbo.Tmp_SI_Provider_Profile SET (LOCK_ESCALATION = TABLE)
            GO
            ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
                DF_SI_Provider_Profile_SIdtDateTimeStamp DEFAULT (getdate()) FOR SI_dtDate_Time_Stamp
            GO
            ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
                DF_SI_Provider_Profile_SIbHotelPreLoaded DEFAULT ((0)) FOR SI_bHotel_Pre_Loaded
            GO
            IF EXISTS(SELECT * FROM dbo.SI_Provider_Profile)
                 EXEC('INSERT INTO dbo.Tmp_SI_Provider_Profile (SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName)
                    SELECT SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName FROM dbo.SI_Provider_Profile WITH (HOLDLOCK TABLOCKX)')
            GO

            -- Rename the primary key constraint or unique key In SQL Server constraints such as primary keys or foreign keys are objects in their own right, even though they are dependent upon the "containing" table.
            EXEC sp_rename 'dbo.SI_Provider_Profile.PK_SI_Provider_Profile', 'PK_SI_Provider_Profile_Old';
            GO
            -- backup old table in case of 
            EXECUTE sp_rename N'dbo.SI_Provider_Profile', N'SI_Provider_Profile_Old', 'OBJECT'
            GO

            EXECUTE sp_rename N'dbo.Tmp_SI_Provider_Profile', N'SI_Provider_Profile', 'OBJECT'
            GO

            ALTER TABLE dbo.SI_Provider_Profile ADD CONSTRAINT
                PK_SI_Provider_Profile PRIMARY KEY NONCLUSTERED 
                (
                SI_lProvider_Profile_ID
                ) WITH( PAD_INDEX = OFF, FILLFACTOR = 90, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

            GO
            COMMIT TRANSACTION

=============================

0
Cena Jang

Juste pour quelqu'un qui a le même problème que moi… .. Si vous voulez juste faire quelques insertions juste une fois, vous pouvez faire quelque chose comme ça.

Supposons que vous ayez une table avec deux colonnes

ID Identity (1,1) | Name Varchar

et vous souhaitez insérer une ligne avec l'ID = 4. Vous devez donc le redéfinir à 3 pour que le suivant soit 4

DBCC CHECKIDENT([YourTable], RESEED, 3)

Faire l'insert

INSERT  INTO [YourTable]
        ( Name )
VALUES  ( 'Client' )

Et ramenez votre graine à l'ID le plus élevé, supposons 15

DBCC CHECKIDENT([YourTable], RESEED, 15)

Terminé!

0
Faruk Feres