web-dev-qa-db-fra.com

Ajout d'une identité à une colonne existante

Je dois changer la clé primaire d'une table en une colonne d'identité, et il y a déjà plusieurs lignes dans la table.

J'ai un script pour nettoyer les identifiants afin de s'assurer qu'ils sont séquentiels à partir de 1, fonctionne bien sur ma base de données de test.

Quelle est la commande SQL pour modifier la colonne pour avoir une propriété d'identité?

406
Kirschstein

Vous ne pouvez pas modifier les colonnes existantes pour l'identité.

Vous avez 2 options,

  1. Créer une nouvelle table avec identité & supprimer la table existante

  2. Créer une nouvelle colonne avec identité et supprimer la colonne existante

Méthode 1. ( Nouvelle table ) Vous pouvez conserver ici les valeurs de données existantes dans la colonne d'identité nouvellement créée.

CREATE TABLE dbo.Tmp_Names
    (
      Id int NOT NULL
             IDENTITY(1, 1),
      Name varchar(50) NULL
    )
ON  [PRIMARY]
go

SET IDENTITY_INSERT dbo.Tmp_Names ON
go

IF EXISTS ( SELECT  *
            FROM    dbo.Names ) 
    INSERT  INTO dbo.Tmp_Names ( Id, Name )
            SELECT  Id,
                    Name
            FROM    dbo.Names TABLOCKX
go

SET IDENTITY_INSERT dbo.Tmp_Names OFF
go

DROP TABLE dbo.Names
go

Exec sp_rename 'Tmp_Names', 'Names'

Méthode 2 ( Nouvelle colonne ) Vous ne pouvez pas conserver les valeurs de données existantes dans la colonne d’identité nouvellement créée. La colonne d’identité contiendra la séquence de chiffres.

Alter Table Names
Add Id_new Int Identity(1, 1)
Go

Alter Table Names Drop Column ID
Go

Exec sp_rename 'Names.Id_new', 'ID', 'Column'

Voir l'article suivant sur le forum Microsoft SQL Server pour plus de détails:

Comment modifier la colonne en identité (1,1)

442
John Sansom

Dans SQL 2005 et versions ultérieures, il existe une astuce pour résoudre ce problème sans modifier les pages de données de la table. Ceci est important pour les grandes tables où toucher chaque page de données peut prendre des minutes ou des heures. L’astuce fonctionne également même si la colonne d’identité est une clé primaire, fait partie d’un index clusterisé ou non clusterisé, ou d’autres pièges qui peuvent tromper la solution plus simple "ajouter/supprimer/renommer une colonne".

Voici l'astuce: vous pouvez utiliser l'instruction ALTER TABLE ... SWITCH de SQL Server pour modifier le schéma d'une table sans modifier les données, ce qui signifie que vous pouvez remplacer une table par une IDENTITY par un schéma de table identique. mais sans colonne IDENTITY. La même astuce consiste à ajouter IDENTITY à une colonne existante.

Normalement, ALTER TABLE ... SWITCH est utilisé pour remplacer efficacement une partition complète dans une table partitionnée par une nouvelle partition vide. Mais il peut également être utilisé dans des tables non partitionnées.

J'ai utilisé cette astuce pour convertir, en moins de 5 secondes, une colonne d'une table de 2,5 milliards de lignes d'IDENTITY en non-IDENTITY (afin d'exécuter une requête de plusieurs heures dont le plan de requête fonctionnait mieux pour les non-IDENTITY. colonnes), puis a restauré le paramètre IDENTITY, à nouveau en moins de 5 secondes.

Voici un exemple de code montrant comment cela fonctionne.

 CREATE TABLE Test
 (
   id int identity(1,1),
   somecolumn varchar(10)
 );

 INSERT INTO Test VALUES ('Hello');
 INSERT INTO Test VALUES ('World');

 -- copy the table. use same schema, but no identity
 CREATE TABLE Test2
 (
   id int NOT NULL,
   somecolumn varchar(10)
 );

 ALTER TABLE Test SWITCH TO Test2;

 -- drop the original (now empty) table
 DROP TABLE Test;

 -- rename new table to old table's name
 EXEC sp_rename 'Test2','Test';

 -- update the identity seed
 DBCC CHECKIDENT('Test');

 -- see same records
 SELECT * FROM Test; 

Ceci est évidemment plus complexe que les solutions des autres réponses, mais si votre table est grande, cela peut vous sauver la vie. Il y a quelques mises en garde:

  • Autant que je sache, l’identité est la seule chose que vous puissiez changer concernant les colonnes de votre table avec cette méthode. L'ajout/suppression de colonnes, la modification de la nullité, etc. n'est pas autorisée.
  • Vous devrez abandonner les clés pour vous avant de faire le changement et les restaurer après.
  • Idem pour WITH SCHEMABINDING, fonctions, vues, etc.
  • les index de la nouvelle table doivent correspondre exactement (mêmes colonnes, même ordre, etc.)
  • Les anciennes et les nouvelles tables doivent appartenir au même groupe de fichiers.
  • Ne fonctionne que sur SQL Server 2005 ou version ultérieure
  • Auparavant, je pensais que cette astuce ne fonctionnait que sur les éditions Enterprise ou Developer de SQL Server (car les partitions ne sont prises en charge que par les versions Enterprise et Developer), mais Mason G. Zhwiti, dans son commentaire ci-dessous, indique que cela fonctionne également dans SQL Standard Edition. Je suppose que cela signifie que la restriction à Enterprise ou Developer ne s'applique pas à ALTER TABLE ... SWITCH.

Il y a un bon article sur TechNet détaillant les exigences ci-dessus.

UPDATE - Eric W avait un commentaire ci-dessous qui ajoute des informations importantes sur cette solution. Copiez-le ici pour vous assurer qu'il attire plus d'attention:

Il y a une autre mise en garde ici qui mérite d'être mentionnée. Bien que la nouvelle table reçoive avec plaisir les données de l’ancienne table et que toutes les nouvelles lignes soient insérées suivant un modèle d’identité, elles commenceront à 1 et risquent d’être rompues si ladite colonne est une clé primaire. Pensez à exécuter DBCC CHECKIDENT('<newTableName>') immédiatement après la commutation. Voir msdn.Microsoft.com/en-us/library/ms176057.aspx pour plus d'informations.

Si la table est activement étendue avec de nouvelles lignes (ce qui signifie que vous n'aurez pas beaucoup de temps d'arrêt entre l'ajout de IDENTITY et l'ajout de nouvelles lignes, alors, au lieu de DBCC CHECKIDENT, vous voudrez définir manuellement la valeur de départ de l'identité dans Le nouveau schéma de table doit être supérieur au plus grand ID existant dans la table, par exemple IDENTITY (2435457, 1). Vous pourrez éventuellement inclure à la fois le ALTER TABLE...SWITCH et le DBCC CHECKIDENT dans une transaction (ou non-- cela n’a pas été testé), mais il semble que définir la valeur de départ manuellement sera plus facile et plus sûr.

Évidemment, si aucune nouvelle ligne n'est ajoutée à la table (ou si elle est ajoutée occasionnellement, comme un processus ETL quotidien), cette situation de concurrence critique ne se produira pas, donc DBCC CHECKIDENT est correct.

190
Justin Grant

Vous ne pouvez pas transformer une colonne en une colonne IDENTITY. Ce que vous devez faire est de créer une nouvelle colonne qui est définie comme une IDENTITÉ dès le début, puis supprimez l'ancienne colonne et renommez la nouvelle en son ancien nom.

ALTER TABLE (yourTable) ADD NewColumn INT IDENTITY(1,1)

ALTER TABLE (yourTable) DROP COLUMN OldColumnName

EXEC sp_rename 'yourTable.NewColumn', 'OldColumnName', 'COLUMN'

Marc

64
marc_s

Il existe une solution intéressante décrite ici: SQL SERVER - Ajout ou suppression d’une propriété d’identité sur une colonne

En bref, éditez manuellement votre table dans SQL Manager, changez l’identité, NE PAS ENREGISTRER les modifications, affichez simplement le script qui sera créé pour les modifications, copiez-la et utilisez-la plus tard.

C'est un gain de temps considérable, car il (le script) contient toutes les clés étrangères, index, etc. liés à la table que vous modifiez. Ecrire ceci manuellement ... Dieu nous en préserve.

14
greenoldman

Considérez utiliser SEQUENCE au lieu de IDENTITY .

Dans le serveur SQL 2014 (je ne connais pas les versions inférieures), vous pouvez le faire simplement, en utilisant la séquence.

CREATE SEQUENCE  sequence_name START WITH here_higher_number_than_max_existed_value_in_column INCREMENT BY 1;

ALTER TABLE table_name ADD CONSTRAINT constraint_name DEFAULT NEXT VALUE FOR sequence_name FOR column_name

À partir de là: séquence comme valeur par défaut pour une colonne

6
OTAR

Explication simple

Renommez la colonne existante à l'aide de sp_RENAME.

EXEC sp_RENAME 'Nom_Table.NomExistant_Colonne', 'Nouveau_NomColonne', 'COLUMN'

Exemple pour renommer:

La colonne existante UserID est renommée OldUserID.

EXEC sp_RENAME 'AdminUsers.UserID' , 'OldUserID', 'COLUMN'

Ajoutez ensuite une nouvelle colonne à l'aide de alter query pour la définir comme clé primaire et valeur d'identité.

ALTER TABLE TableName ADD Old_ColumnName INT NOT NULL PRIMARY KEY IDENTITY(1,1)

Exemple pour définir la clé primaire

Le nouveau nom de colonne créé est UserID.

ALTER TABLE Users ADD UserID INT NOT NULL PRIMARY KEY IDENTITY(1,1)

puis déposez la colonne renommée

ALTER TABLE Table_Name DROP COLUMN Renamed_ColumnName

Exemple pour Drop colonne renommée

ALTER TABLE Users DROP COLUMN OldUserID

Nous avons ajouté une clé primaire et une identité à la colonne existante de la table.

6
Sathish Chelladurai

Je suis un développeur Java qui s'est retrouvé dans une équipe sans DBA et dans lequel, en tant que développeur, je ne peux pas obtenir les droits DBA. J'avais pour tâche de déplacer un schéma complet entre deux bases de données. Par conséquent, sans administrateur de base de données, je devais le faire et le faire en exécutant des scripts, sans pouvoir utiliser l'interface graphique dans SQL Server 2008, car je ne disposais pas de privilèges d'administrateur.

Tout a été déplacé sans problème, cependant, lors de l'exécution d'une procédure stockée sur la nouvelle table schema.table, j'ai constaté que j'avais perdu le champ d'identité d'une table. J'ai vérifié le script qui a créé la table et il était là, cependant, SQL Server ne l'a pas eu lorsque j'ai exécuté le script. Un administrateur de base de données m'a dit plus tard qu'il avait déjà rencontré le même problème auparavant.

En tout état de cause, pour SQL Server 2008, voici les étapes que j’ai prises pour résoudre ce problème et qui ont fonctionné. C’est pourquoi j’affiche ceci ici dans l’espoir que ce sera une aide pour quelqu'un. C'est ce que j'ai fait car j'avais des dépendances FK sur une autre table, ce qui rendait la tâche plus difficile:

J'ai utilisé cette requête pour vérifier que l'identité était effectivement manquante et pour afficher les dépendances sur la table.

1.) Trouver des statistiques sur un tableau:

exec sp_help 'dbo.table_name_old';

2.) Créez une nouvelle table identique en double, à l'exception de l'ajout d'un champ d'identité sur le champ PK où il se trouvait auparavant.

3.) Désactivez l'identité pour déplacer les données.

SET IDENTITY_INSERT dbo.table_name ON 

4.) Transférez les données.

INSERT INTO dbo.table_name_new
(
field1, field2, etc...
)
SELECT 
field1, field2, etc...
FROM 
dbo.table_name_old;

5.) Vérifiez que les données sont là.

SELECT * FROM dbo.table_name_new

6.) Réactivez l'identité.

SET IDENTITY_INSERT ToyRecP.ToyAwards.lkpFile_New OFF

7.) C'est le meilleur script que j'ai trouvé pour obtenir toutes les relations FK afin de vérifier quelle (s) table (s) la table d'origine faisait référence à des dépendances et j'en ai rencontré beaucoup, donc c'est un gardien!

SELECT f.name AS ForeignKey,
   OBJECT_NAME(f.parent_object_id) AS TableName,
   COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
   OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
   COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
   ON f.OBJECT_ID = fc.constraint_object_id
   ORDER BY ReferenceTableName;

8.) Assurez-vous de disposer de tous les scripts PK et FK pour toutes les tables concernées avant la prochaine étape.

9.) Vous pouvez cliquer avec le bouton droit sur chaque clé et écrire un script à l'aide de SQL Server 2008.

10.) Supprimez le ou les FK de la ou des tables de dépendance en utilisant la syntaxe suivante:

ALTER TABLE [dbo].[table_name] DROP CONSTRAINT [Name_of_FK]

11.) Déposer la table d'origine:

DROP TABLE dbo.table_name_old;

13.) Ces étapes suivantes reposent sur les scripts que vous avez créés dans SQL Server 2008 à l'étape 9.

--Ajouter le PK à la nouvelle table.

--Ajouter le FK à la nouvelle table.

--Ajouter le FK à la table de dépendance.

14.) Vérifiez que tout est correct et complet. J'ai utilisé l'interface graphique pour regarder les tables.

15.) Renommez la nouvelle table avec le nom de la table originale.

exec sp_RENAME '[Schema_Name.OldTableName]' , '[NewTableName]';

Enfin, tout a fonctionné!

5
James Drinkard

Comme je l'ai compris dans les cas normaux, nous créons une table avec clé primaire qui est en train d'avoir propriété d'identité
Donc renommer ou supprimer une colonne associée à clé primairecontrainte ne sera pas possible parce que contrainte Les règles valident la structure des colonnes.
Pour y parvenir, nous devons procéder de la manière suivante:
Supposons que TableName = 'Employee' et ColumnName = 'EmployeeId'

1. Ajouter une nouvelle colonne 'EmployeeId_new' dans la table 'Employee'
ALTER TABLE Employee ADD EmployeeId_new INT IDENTITY (1,1)

  1. Maintenant, supprimez la colonne 'EmployeeId' de la table 'Employee'
    ALTER TABLE Employé DROP COLUMN EmployeeId

  2. Cela provoquera une erreur car les règles de contrainte de clé primaire s'appliquent et valident la structure de colonne.
    * ### ' Msg 5074, niveau 16, état 1, ligne 1 L'objet [PK_dbo.Employee] dépend de colmn [EmployeeId].' ###

  3. Nous devons donc d'abord supprimer la contrainte de clé primaire de la table 'Employé', puis supprimer la colonne.
    contrainte ALTER TABLE Employee DROP [PK_dbo.Employee]

  4. Maintenant, nous pouvons supprimer la colonne 'EmployeeId' du tableau 'Employee' comme à l'étape précédente où nous avons eu une erreur
    ALTER TABLE Employé DROP COLUMN EmployeeId

  5. Maintenant, la colonne 'EmployeeId' est supprimée de la table. Nous allons donc renommer la nouvelle colonne 'EmployeeId_new' récemment ajoutée avec 'EmployeeId'
    sp_rename 'Employee.EmployeeId', 'EmployeeId_new', 'COLUMN'

  6. Pour réorganiser la table sous la même forme, il faut ajouter une contrainte de clé primaire à la colonne 'EmployeeId'
    La clé primaire d'ALTER TABLE Employee add [PK_dbo.Employee] (EmployeeId)

8. La table 'Employee' avec 'EmployeeId' est maintenant modifiée pour les règles d'identité avec la contrainte de clé primaire existante

4
Rinku

De par leur conception, il n'existe pas de moyen simple d'activer ou de désactiver la fonctionnalité d'identité pour une colonne existante. Le seul moyen propre de le faire est de créer une nouvelle colonne et d'en faire une colonne d'identité ou de créer une nouvelle table et de migrer vos données.

Si nous utilisons SQL Server Management Studio pour supprimer la valeur d'identité de la colonne "id", une nouvelle table temporaire est créée, les données sont déplacées vers la table temporaire, l'ancienne table est supprimée et la nouvelle table est renommée.

Utilisez Management Studio pour effectuer la modification, puis cliquez avec le bouton droit de la souris sur le concepteur et sélectionnez "Générer le script de modification".

Vous verrez que c'est ce que le serveur SQL fait en arrière-plan.

3
Raj

vous ne pouvez pas le faire comme cela, vous devez ajouter une autre colonne, supprimer la colonne d'origine et renommer la nouvelle colonne ou créer une nouvelle table, copier les données et supprimer l'ancienne table, puis renommer la nouvelle table en ancienne table

si vous utilisez SSMS et définissez la propriété identity sur ON dans le concepteur, voici ce que SQL Server fait en arrière-plan. Donc, si vous avez une table nommée [utilisateur], c’est ce qui se passe si vous indiquez l’identifiant et l’identité

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
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

GO
CREATE TABLE dbo.Tmp_User
    (
    UserID int NOT NULL IDENTITY (1, 1),
    LastName varchar(50) NOT NULL,
    FirstName varchar(50) NOT NULL,
    MiddleInitial char(1) NULL

    )  ON [PRIMARY]
GO

SET IDENTITY_INSERT dbo.Tmp_User ON
GO
IF EXISTS(SELECT * FROM dbo.[User])
 EXEC('INSERT INTO dbo.Tmp_User (UserID, LastName, FirstName, MiddleInitial)
    SELECT UserID, LastName, FirstName, MiddleInitialFROM dbo.[User] TABLOCKX')
GO
SET IDENTITY_INSERT dbo.Tmp_User OFF
GO

GO
DROP TABLE dbo.[User]
GO
EXECUTE sp_rename N'dbo.Tmp_User', N'User', 'OBJECT'
GO
ALTER TABLE dbo.[User] ADD CONSTRAINT
    PK_User PRIMARY KEY CLUSTERED 
    (
    UserID
    ) ON [PRIMARY]

GO
COMMIT

Cela dit, il existe un moyen de pirater la table système pour y parvenir en définissant la valeur au niveau du bit, mais cela n'est pas pris en charge et je ne le ferais pas.

3
SQLMenace

Pour modifier les propriétés d'identité d'une colonne:

  • Dans l'Explorateur de serveurs, cliquez avec le bouton droit sur la table avec les propriétés d'identité que vous souhaitez modifier, puis cliquez sur Ouvrir la définition de table. La table s'ouvre dans Table Designer.
  • Désactivez la case à cocher Autoriser les valeurs NULL pour la colonne que vous souhaitez modifier.
  • Dans l'onglet Propriétés de la colonne, développez la propriété Spécification d'identité.
  • Cliquez sur la cellule de la grille pour la propriété enfant Is Identity et choisissez Oui dans la liste déroulante.
  • Saisissez une valeur dans la cellule Identity Seed. Cette valeur sera affectée à la première ligne du tableau. La valeur 1 sera attribuée par défaut.

Ça y est, et ça a fonctionné pour moi

2
Ken.Fukizi

Si vous utilisez Visual Studio 2017+

  1. Dans Server Object Explorer, cliquez avec le bouton droit de la souris sur votre table et sélectionnez "Afficher le code".
  2. Ajoutez le modificateur "IDENTITY" à votre colonne
  3. Mise à jour

Cela fera tout pour vous.

2
jdisla

Il n'y en a pas, malheureusement; la propriété IDENTITY appartient à la table plutôt qu'à la colonne.

Le moyen le plus simple est de le faire dans l'interface graphique, mais si ce n'est pas une option, vous pouvez faire un grand bout de chemin en copiant les données, en supprimant la colonne, en l'ajoutant à nouveau à l'identité et en rétablissant les données.

Voir ici pour un compte détaillé.

2
Jeremy Smyth

Cliquez avec le bouton droit sur le nom de la table dans l'Explorateur d'objets. Vous obtiendrez des options. Cliquez sur 'Design'. Un nouvel onglet sera ouvert pour cette table. Vous pouvez ajouter une contrainte d'identité ici dans les "Propriétés de la colonne".

2
vamsi_874

Si l’affiche originale voulait réellement définir une colonne existante comme un PRIMARY KEY pour la table et n’avait en fait pas besoin que la colonne soit une colonne IDENTITY (deux choses différentes), vous pouvez le faire via t-SQL avec:

ALTER TABLE [YourTableName]
ADD CONSTRAINT [ColumnToSetAsPrimaryKey] PRIMARY KEY ([ColumnToSetAsPrimaryKey])

Notez les parenthèses autour du nom de la colonne après l'option PRIMARY KEY.

Bien que cet article soit ancien et que je fasse une hypothèse sur les besoins des demandeurs, j’ai pensé que ces informations supplémentaires pourraient être utiles aux utilisateurs rencontrant ce fil, car je pense que la conversation pourrait laisser croire qu’une colonne existante ne peut pas être définie comme une clé primaire sans l'ajouter en tant que nouvelle colonne, ce qui serait incorrect.

1
A. Omalley

Selon mon état actuel, je suis cette approche. Je souhaite attribuer une identité à une table primaire après l’insertion de données via un script.

Comme je veux ajouter une identité, cela commence donc toujours de 1 à la fin du nombre d'enregistrements que je veux.

--first drop column and add with identity
ALTER TABLE dbo.tblProductPriceList drop column ID 
ALTER TABLE dbo.tblProductPriceList add ID INT IDENTITY(1,1)

--then add primary key to that column (exist option you can ignore)
IF  NOT EXISTS (SELECT * FROM sys.key_constraints  WHERE object_id = OBJECT_ID(N'[dbo].[PK_tblProductPriceList]') AND parent_object_id = OBJECT_ID(N'[dbo].[tblProductPriceList]'))
    ALTER TABLE [tblProductPriceList] ADD PRIMARY KEY (id)
GO

Cela créera la même colonne de clé primaire avec identité.

J'ai utilisé ces liens: https://blog.sqlauthority.com/2014/10/11/sql-server-add-auto-incremental-identity-column-to-table-after-creating-table/

Ajouter une clé primaire à la table existante

1
Ajay2707

Fondamentalement, il y a quatre étapes logiques.

  1. Créez une nouvelle colonne d'identité. Activez Insérer identité pour cette nouvelle colonne.

  2. Insérez les données de la colonne source (la colonne que vous souhaitez convertir en identité) dans cette nouvelle colonne.

  3. Désactivez l'insertion d'identité pour la nouvelle colonne.

  4. Supprimez votre colonne source et renommez la nouvelle colonne avec le nom de la colonne source.

Il peut y avoir plus de complexité, comme travailler sur plusieurs serveurs, etc.

Veuillez vous reporter à l'article suivant pour les étapes (en utilisant ssms & T-sql). Ces étapes sont destinées aux débutants maîtrisant moins T-SQL.

http://social.technet.Microsoft.com/wiki/contents/articles/23816.how-to-convert-int-column-to-identity-in-the-ms-sql-server.aspx

0

Je ne crois pas que vous puissiez modifier une colonne existante en une colonne d'identité à l'aide de tsql. Cependant, vous pouvez le faire via la vue de conception d'Enterprise Manager.

Vous pouvez également créer une nouvelle ligne en tant que colonne d'identité, supprimer l'ancienne colonne, puis renommer votre nouvelle colonne.

ALTER TABLE FooTable
ADD BarColumn INT IDENTITY(1, 1)
               NOT NULL
               PRIMARY KEY CLUSTERED
0
William Edmondson

génère un script pour toutes les tables avec la clé primaire = bigint qui n'ont pas d'identité définie; cela retournera une liste de scripts générés avec chaque table;

SET NOCOUNT ON;

declare @sql table(s varchar(max), id int identity)

DECLARE @table_name nvarchar(max),
        @table_schema nvarchar(max);

DECLARE vendor_cursor CURSOR FOR 
SELECT
  t.name, s.name
FROM sys.schemas AS s
INNER JOIN sys.tables AS t
  ON s.[schema_id] = t.[schema_id]
WHERE EXISTS (
    SELECT
    [c].[name]
    from sys.columns [c]
    join sys.types [y] on [y].system_type_id = [c].system_type_id
    where [c].[object_id] = [t].[object_id] and [y].name = 'bigint' and [c].[column_id] = 1
) and NOT EXISTS 
(
  SELECT 1 FROM sys.identity_columns
    WHERE [object_id] = t.[object_id]
) and exists (
    select 1 from sys.indexes as [i] 
    inner join sys.index_columns as [ic]  ON  i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
    where object_name([ic].[object_id]) = [t].[name]
)
OPEN vendor_cursor

FETCH NEXT FROM vendor_cursor 
INTO @table_name, @table_schema

WHILE @@FETCH_STATUS = 0
BEGIN

DELETE FROM @sql

declare @pkname varchar(100),
    @pkcol nvarchar(100)

SELECT  top 1
        @pkname = i.name,
        @pkcol = COL_NAME(ic.OBJECT_ID,ic.column_id)
FROM    sys.indexes AS [i]
INNER JOIN sys.index_columns AS [ic] ON  i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
WHERE   i.is_primary_key = 1 and OBJECT_NAME(ic.OBJECT_ID) = @table_name

declare @q nvarchar(max) = 'SELECT  '+@pkcol+' FROM ['+@table_schema+'].['+@table_name+'] ORDER BY '+@pkcol+' DESC'

DECLARE @ident_seed nvarchar(max) -- Change this to the datatype that you are after
SET @q = REPLACE(@q, 'SELECT', 'SELECT TOP 1 @output = ')
EXEC sp_executeSql @q, N'@output bigint OUTPUT', @ident_seed OUTPUT

insert into  @sql(s) values ('BEGIN TRANSACTION')
insert into  @sql(s) values ('BEGIN TRY')

-- create statement
insert into  @sql(s) values ('create table ['+@table_schema+'].[' + @table_name + '_Temp] (')

-- column list
insert into @sql(s) 
select 
    '  ['+[c].[name]+'] ' +
    y.name + 

    (case when [y].[name] like '%varchar' then
    coalesce('('+(case when ([c].[max_length] < 0 or [c].[max_length] >= 1024) then 'max' else cast([c].max_length as varchar) end)+')','')
    else '' end)

     + ' ' +
    case when [c].name = @pkcol then 'IDENTITY(' +COALESCE(@ident_seed, '1')+',1)' else '' end + ' ' +
    ( case when c.is_nullable = 0 then 'NOT ' else '' end ) + 'NULL ' + 
    coalesce('DEFAULT ('+(
        REPLACE(
            REPLACE(
                LTrim(
                    RTrim(
                        REPLACE(
                            REPLACE(
                                REPLACE(
                                    REPLACE(
                                        LTrim(
                                            RTrim(
                                                REPLACE(
                                                    REPLACE(
                                                        object_definition([c].default_object_id)
                                                    ,' ','~')
                                                ,')',' ')
                                            )
                                        )
                                    ,' ','*')
                                ,'~',' ')
                            ,' ','~')
                        ,'(',' ')
                    )
                )
            ,' ','*')
        ,'~',' ')
    ) +
    case when object_definition([c].default_object_id) like '%get%date%' then '()' else '' end
    +
    ')','') + ','
 from sys.columns c
 JOIN sys.types y ON y.system_type_id = c.system_type_id
  where OBJECT_NAME(c.[object_id]) = @table_name and [y].name != 'sysname'
 order by [c].column_id


 update @sql set s=left(s,len(s)-1) where id=@@identity

-- closing bracket
insert into @sql(s) values( ')' )

insert into @sql(s) values( 'SET IDENTITY_INSERT ['+@table_schema+'].['+@table_name+'_Temp] ON')

declare @cols nvarchar(max)
SELECT @cols = STUFF(
    (
        select ',['+c.name+']'
        from sys.columns c
        JOIN sys.types y ON y.system_type_id = c.system_type_id
        where c.[object_id] = OBJECT_ID(@table_name)
        and [y].name != 'sysname'
        and [y].name != 'timestamp'
        order by [c].column_id
        FOR XML PATH ('')
     )
    , 1, 1, '')

insert into @sql(s) values( 'IF EXISTS(SELECT * FROM ['+@table_schema+'].['+@table_name+'])')
insert into @sql(s) values( 'EXEC(''INSERT INTO ['+@table_schema+'].['+@table_name+'_Temp] ('+@cols+')')
insert into @sql(s) values( 'SELECT '+@cols+' FROM ['+@table_schema+'].['+@table_name+']'')')

insert into @sql(s) values( 'SET IDENTITY_INSERT ['+@table_schema+'].['+@table_name+'_Temp] OFF')


insert into @sql(s) values( 'DROP TABLE ['+@table_schema+'].['+@table_name+']')

insert into @sql(s) values( 'EXECUTE sp_rename N''['+@table_schema+'].['+@table_name+'_Temp]'', N'''+@table_name+''', ''OBJECT''')

if ( @pkname is not null ) begin
    insert into @sql(s) values('ALTER TABLE ['+@table_schema+'].['+@table_name+'] ADD CONSTRAINT ['+@pkname+'] PRIMARY KEY CLUSTERED (')
    insert into @sql(s)
        select '  ['+COLUMN_NAME+'] ASC,' from information_schema.key_column_usage
        where constraint_name = @pkname
        GROUP BY COLUMN_NAME, ordinal_position
        order by ordinal_position

    -- remove trailing comma
    update @sql set s=left(s,len(s)-1) where id=@@identity
    insert into @sql(s) values ('  )')
end

insert into  @sql(s) values ('--Run your Statements')
insert into  @sql(s) values ('COMMIT TRANSACTION')
insert into  @sql(s) values ('END TRY')
insert into  @sql(s) values ('BEGIN CATCH')
insert into  @sql(s) values ('        ROLLBACK TRANSACTION')
insert into  @sql(s) values ('        DECLARE @Msg NVARCHAR(MAX)  ')
insert into  @sql(s) values ('        SELECT @Msg=ERROR_MESSAGE() ')
insert into  @sql(s) values ('        RAISERROR(''Error Occured: %s'', 20, 101,@msg) WITH LOG')
insert into  @sql(s) values ('END CATCH')

declare @fqry nvarchar(max)

-- result!
SELECT @fqry = (select char(10) + s from @sql order by id FOR XML PATH (''))


SELECT @table_name as [Table_Name], @fqry as [Generated_Query]
PRINT 'Table: '+@table_name
EXEC sp_executeSql @fqry

    FETCH NEXT FROM vendor_cursor 
    INTO @table_name, @table_schema
END 
CLOSE vendor_cursor;
DEALLOCATE vendor_cursor;
0
Kyle Gibbar