Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

SQL Server, Comment définir l'incrémentation automatique après la création d'une table sans perte de données ?

Modification de l'IDENTITY propriété est vraiment un changement de métadonnées uniquement. Mais pour mettre à jour les métadonnées directement, il faut démarrer l'instance en mode mono-utilisateur et jouer avec certaines colonnes dans sys.syscolpars et n'est pas documenté/non pris en charge et ce n'est pas quelque chose que je recommanderais ou sur lequel je donnerai des détails supplémentaires.

Pour les personnes rencontrant cette réponse sur SQL Server 2012+, le moyen de loin le plus simple d'obtenir ce résultat d'une colonne à incrémentation automatique serait de créer une SEQUENCE objet et définissez la next value for seq comme colonne par défaut.

Alternativement, ou pour les versions précédentes (à partir de 2005), la solution de contournement publiée sur cet élément de connexion montre une manière entièrement prise en charge de le faire sans avoir besoin d'opérations de taille de données à l'aide de ALTER TABLE...SWITCH . A également blogué sur MSDN ici. Bien que le code pour y parvenir ne soit pas très simple et qu'il existe des restrictions - telles que la table en cours de modification ne peut pas être la cible d'une contrainte de clé étrangère.

Exemple de code.

Configurer une table de test sans identity colonne.

CREATE TABLE dbo.tblFoo 
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)


INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2

Modifiez-le pour avoir une identity colonne (plus ou moins instantanée).

BEGIN TRY;
    BEGIN TRANSACTION;

    /*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
      set the correct seed in the table definition instead*/
    DECLARE @TableScript nvarchar(max)
    SELECT @TableScript = 
    '
    CREATE TABLE dbo.Destination(
        bar INT IDENTITY(' + 
                     CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1)  PRIMARY KEY,
        filler CHAR(8000),
        filler2 CHAR(49)
        )

        ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
    '       
    FROM dbo.tblFoo
    WITH (TABLOCKX,HOLDLOCK)

    EXEC(@TableScript)


    DROP TABLE dbo.tblFoo;

    EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';


    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
    PRINT ERROR_MESSAGE();
END CATCH;

Testez le résultat.

INSERT INTO dbo.tblFoo (filler,filler2) 
OUTPUT inserted.*
VALUES ('foo','bar')

Donne

bar         filler    filler2
----------- --------- ---------
10001       foo       bar      

Nettoyer

DROP TABLE dbo.tblFoo