Ajout d'une identité à une colonne existante

je dois changer la clé primaire d'une table à une colonne d'identité, et il y a déjà un certain nombre de lignes dans la table.

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

Qu'est-ce que la commande SQL pour modifier la colonne pour avoir une propriété d'identité?

353
demandé sur John Saunders 2009-06-26 17:41:21

19 réponses

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

vous avez 2 options,

  1. "créer une nouvelle table avec Identité et supprimer la table existante

  2. créer une nouvelle colonne avec Identité et supprimer la colonne existante

approche 1. ( nouveau tableau ) ici vous pouvez conserver les valeurs de données existantes sur le 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'

approche 2 ( nouvelle colonne ) vous ne pouvez pas conserver les valeurs de données existantes sur la nouvelle colonne identité, la colonne identité contiendra la séquence du numéro.

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 le Microsoft SQL Server Forum post pour plus de détails:

Comment modifier colonne identity(1,1)

389
répondu John Sansom 2013-12-13 19:09:44

en SQL 2005 et au-dessus, il y a un truc pour résoudre ce problème sans changer 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 aussi même si la colonne identité est une clé primaire, fait partie d'un index groupé ou non groupé, ou d'autres gotchas qui peuvent déclencher la solution la plus simple "Ajouter/Supprimer/Renommer la colonne".

voici le truc: vous pouvez utiliser SQL Server's ALTER TABLE...Basculer déclaration pour changer le schéma d'une table sans changer les données, ce qui signifie que vous pouvez remplacer une table avec une identité avec un schéma de table identique, mais sans colonne D'identité. Le même truc fonctionne pour ajouter de l'identité à une colonne existante.

normalement, modifier la TABLE...Le commutateur 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 les tables non-divisées aussi.

j'ai utilisé cette astuce pour convertir, en moins de 5 secondes, une colonne de A d'une table de ligne de 2,5 milliards de L'identité à une non-identité (afin d'exécuter une requête de plusieurs heures dont le plan de requête a fonctionné mieux pour les colonnes de non-identité), puis restauré le réglage de L'identité, encore une fois en moins de 5 secondes.

voici un exemple de code de comment ça marche.

 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; 

c'est évidemment plus impliqué que le solutions dans d'autres réponses, mais si votre table est grande, cela peut être un vrai gain de vie. Il y a quelques mises en garde:

  • autant que je sache, l'identité est la seule chose que vous pouvez changer sur les colonnes de votre table avec cette méthode. Ajout / Suppression de colonnes, modification de la nullité, etc. n'est pas autorisé.
  • vous aurez besoin de déposer les clés foriegn avant de faire le commutateur et de les restaurer après.
  • même pour avec SCHEMABINDING fonctions, vues, etc.
  • nouvelle table de l'index doivent correspondre exactement (mêmes colonnes, même ordre, etc.)
  • tables anciennes et nouvelles doivent être sur le même groupe de fichiers.
  • ne fonctionne que sur SQL Server 2005 ou après
  • j'ai déjà cru que cette astuce ne fonctionne que sur les versions Enterprise ou Developer de SQL Server( parce que les partitions ne sont supportées que dans les versions Enterprise et Developer), mais Mason G. Zhwiti dans son commentaire ci-dessous dit qu'il fonctionne également dans L'Édition Standard SQL aussi. Je suppose que cela signifie que la restriction à L'entreprise ou le développeur ne s'applique pas à modifier la TABLE...COMMUTATEUR.

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

UPDATE - Eric Wu avait un commentaire ci-dessous qui ajoute des informations importantes sur cette solution. Le copier ici pour s'assurer qu'il obtient plus d'attention:

il y a une autre mise en garde qui vaut la peine d'être mentionnée. Bien que les nouvelle table recevra volontiers des données de l'ancienne table, et tous les de nouvelles lignes seront insérées suivant un modèle d'identité, elles seront commencer à 1 et potentiellement briser si la colonne est une clé primaire. Envisagez de lancer DBCC CHECKIDENT('<newTableName>') immédiatement après commutation. Voir msdn.microsoft.com/en-us/library/ms176057.aspx pour plus info.

si la table est activement prolongée avec de nouvelles lignes (ce qui signifie que vous n'avez pas beaucoup de temps d'arrêt entre l'ajout de L'identité et l'ajout de nouvelles lignes, puis à la place de DBCC CHECKIDENT vous voudrez définir manuellement la valeur de graine d'identité dans le nouveau schéma de table pour être plus grand que le plus grand ID existant dans la table, par exemple IDENTITY (2435457, 1) . Vous pourriez être en mesure d'inclure à la fois le ALTER TABLE...SWITCH et le DBCC CHECKIDENT dans une transaction (ou non-n'avez pas testé ce) mais il semble que le réglage manuel de la valeur de graine sera plus facile et plus sûr.

évidemment, si aucune nouvelle ligne n'est ajoutée à la table (ou si elles ne sont ajoutées qu'occasionnellement, comme un processus quotidien ETL) alors cette condition de course ne se produira pas donc DBCC CHECKIDENT est très bien.

171
répondu Justin Grant 2018-06-29 18:35:42

vous ne pouvez pas modifier une colonne pour en faire une colonne D'identité. Ce que vous devez faire est de créer une nouvelle colonne qui est définie comme une IDENTITÉ à partir de l'obtenir-aller, puis supprimer l'ancienne colonne, et renommer le nouveau à l'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

60
répondu marc_s 2017-01-10 15:30:36

il y a une solution fraîche décrite ici: SQL SERVER – pour Ajouter ou Supprimer l'Identité de Propriété sur la Colonne

en bref éditez manuellement votre table dans SQL Manager, changez l'identité, ne sauvegardez pas les modifications, montrez simplement le script qui sera créé pour les modifications, Copiez-le et utilisez-le plus tard.

c'est un gain de temps énorme, car il (le script) contient toutes les clés étrangères, les indices, etc. liées à la table que vous changez. La rédaction de cette manuellement... À dieu ne plaise.

13
répondu greenoldman 2013-12-13 19:09:21

explication Simple

renommer la colonne existante en utilisant sp_RENAME

EXEC sp_RENAME ' Table_Name.Existing_ColumnName',' New_ColumnName',' COLUMN '

exemple pour renommer:

la colonne UserID existante est renommée OldUserID

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

puis Ajouter une nouvelle colonne en utilisant alter query pour définir la clé primaire et valeur d'identité

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

exemple de clé primaire 151980920"

le nom de la nouvelle colonne créée est UserID

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

puis supprimer la colonne renommée

ALTER TABLE Table_Name DROP COLUMN Renamed_ColumnName

exemple de Drop renommé colonne

ALTER TABLE Users DROP COLUMN OldUserID

maintenant nous avons ajouté une clé primaire et l'identité à la colonne existante sur la table.

5
répondu Sathish Chelladurai 2014-12-29 16:13:02

dans sql server 2014 (Je ne sais pas pour les versions inférieures) vous pouvez le faire simplement, en utilisant sequence.

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

D'ici: séquence comme valeur par défaut pour une colonne

4
répondu OTAR 2017-05-23 12:34:53

je suis un développeur java qui s'est avéré pour obtenir sur une équipe sans DBA et un où en tant que développeur, Je ne peux pas obtenir des droits DBA. J'ai été chargé de déplacer un schéma entier entre deux bases de données, donc sans avoir de DBA, j'ai dû le faire et le faire en exécutant des scripts, ne pouvant pas utiliser L'interface graphique dans SQL Server 2008 parce que je n'avais pas de privilèges d'administration.

Tout a été déplacé sans problème, cependant, lors de l'exécution d'une procédure stockée sur le nouveau schéma.tableau, j'ai découvert que j' perdu l'identité champ dans une table. J'ai vérifié le script qui a créé la table et il était là, cependant, SQL Server ne l'a pas reçu quand j'ai lancé le script. J'ai été informé plus tard par un DBA qu'il avait vu ce même problème avant.

dans tous les cas, pour SQL Server 2008, ce sont les étapes que j'ai prises pour obtenir cette résolution et ils ont fonctionné, donc je poste ceci ici dans l'espoir qu'il sera une aide à quelqu'un. C'est ce que j'ai fait car j'avais des dépendances FK sur une autre table qui

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

1.) Trouver des statistiques sur une table:

exec sp_help 'dbo.table_name_old';

2.) Créer un duplicata, une nouvelle table identique, sauf ajouter un champ d'identité sur le champ PK où il était auparavant.

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

SET IDENTITY_INSERT dbo.table_name ON 

4.) Le transfert de la données.

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

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

SELECT * FROM dbo.table_name_new

6. De ré-activer l'identité.

SET IDENTITY_INSERT ToyRecP.ToyAwards.lkpFile_New OFF

7.) C'est le meilleur script que j'ai trouvé pour obtenir tous les FK relations de vérifier à quelle table(s) de la table d'origine des références comme des dépendances et je suis tombé sur 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 que vous avez tous les scripts PK et FK pour toutes les tables concernées, avant la prochaine étape.

9.) Vous pouvez faire un clic droit sur chaque touche et le script en utilisant SQL Server 2008

10.) Supprimer le (s) FK(s) de la (Des) table (s) de dépendances en utilisant cette syntaxe:

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

11.) Supprimer la table originale:

DROP TABLE dbo.table_name_old;

13. Ces prochaines étapes s'appuient 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 les FK de retour à la table des dépendances.

14.) Vérifier que tout est exact et complet. J'ai utilisé l'interface graphique pour regarder les tableaux.

15.) Renommez la nouvelle table pour les tables d'origine nom.

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

enfin, tout a fonctionné!

4
répondu James Drinkard 2018-01-07 13:26:29

de par sa conception, il n'y a pas de façon simple d'allumer ou d'éteindre la caractéristique d'identité d'une colonne existante. Le seul moyen propre de faire cela est de créer une nouvelle colonne et d'en faire une colonne d'identité ou de créer une nouvelle table et la migration de vos données.

si nous utilisons SQL Server Management Studio pour nous débarrasser de la valeur d'identité sur 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 abandonnée et la nouvelle table est renommée.

utilisez Studio de gestion pour faire le changement et puis clic droit dans le concepteur et sélectionnez "Générer Script de changement".

vous verrez que C'est ce que fait SQL server en arrière-plan.

3
répondu Raj 2009-06-26 14:00:39

vous ne pouvez pas le faire comme cela, vous devez ajouter une autre colonne, la chute de la colonne d'origine et de renommer la nouvelle colonne ou ou créer un nouveau tableau, copier les données et la chute de l'ancien tableau suivi de renommer la nouvelle table à l'ancienne table

si vous utilisez SSMS et définissez la propriété identity à ON dans le designer, voici ce que SQL Server fait en coulisse. Donc, si vous avez une table nommée [user] c'est ce qui se passe si vous faites UserID et identity

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

ayant dit qu'il y a un moyen de hacker la table système pour l'accomplir en mettant la valeur bitwise mais qui n'est pas supporté et je ne le ferais pas

3
répondu SQLMenace 2009-06-26 14:06:27

la réponse acceptée est fausse: vous pouvez modifier une colonne existante pour qu'elle soit une identité aussi longtemps que elle ne contient aucune valeur nulle. Après la modification, la graine d'identité commencera à la valeur max(colonne) + 1.

donc ce que vous devez vraiment faire en premier, est de fournir des valeurs pour tous les nulls.

3
répondu Jacob 2014-11-17 18:54:24

comme j'ai compris dans les cas normaux nous créons un tableau avec clé primaire qui a propriété D'identité

Ainsi renommer ou Supprimer une colonne qui est associée à clé primaire contrainte ne sera pas possible parce que les règles de contrainte valident la structure de colonne.

Pour atteindre cela, nous devons traiter certaines étapes de la manière suivante:

Supposons TableName = "Employé" et ColumnName = 'Employé'



1. Ajouter une nouvelle colonne "EmployeeId_new" dans le tableau "Employee"

ALTER TABLE Employee ADD EmployeeId_new INT IDENTITY (1,1)

  1. maintenant supprimer colonne "ID D'employé" du tableau "employé"

    ALTER TABLE Employee DROP COLUMN EmployeeId

  2. Cela permettra de jeter de l'erreur à cause de la Contrainte de Clé Primaire sont soumis à des règles et de la validation de structure de colonne.

    *### ' Msg 5074, Niveau 16, État 1, Ligne 1 L'objet [PK_dbo.L'employé] dépend de colmn [EmployeeId]." ###

  3. nous devons donc supprimer la contrainte principale de la table "employé", puis nous pouvons supprimer la colonne

    ALTER TABLE Employee DROP constraint [PK_dbo.Employé]

  4. maintenant, nous pouvons supprimer la colonne "EmployeeId" de la table "employé" comme dans l'étape précédente où nous avons eu erreur

    ALTER TABLE Colonne Employee DROP Employee ID

  5. Now colonne" EmployeeId " supprimé du tableau Nous allons donc renommer la nouvelle colonne 'EmployeeId_new' avec 'EmployeeId'

    sp_rename 'Employee.Employé', 'EmployeeId_new', 'COLONNE'

  6. pour réorganiser le tableau dans la même forme qu'il était, nous devons ajouter la contrainte principale clé pour la colonne "Employee aid"

    ALTER table Employee add constraint [PK_dbo.Clé primaire (EmployeeId)

8. maintenant le tableau "Employee" avec "EmployeeId" est modifié pour les règles D'identité avec la contrainte principale existante

3
répondu Rinku 2018-01-07 13:50:25

il n'y en a pas, malheureusement; la propriété D'identité appartient à la table plutôt que la colonne.

la manière la plus facile est de le faire dans L'interface graphique, mais si ce n'est pas une option, vous pouvez faire le tour complet en copiant les données, en laissant tomber la colonne, en l'ajoutant de nouveau avec l'identité, et en remettant les données.

Voir ici pour un coup-par-coup compte.

2
répondu Jeremy Smyth 2009-06-26 13:57:06

clic droit sur le nom de la table dans L'Explorateur D'objets. Vous aurez quelques options. Cliquez sur "Design". Un nouvel onglet est ouvert pour cette table. Vous pouvez ajouter une contrainte D'identité ici dans'Propriétés de la colonne'.

2
répondu vamsi_874 2017-06-12 10:37:50

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

  • dans L'Explorateur de serveur, faites un clic droit sur la table avec les propriétés d'identité que vous voulez modifier et cliquez sur Ouvrir La définition de la Table. La table s'ouvre sur Table Designer.
  • effacer la case à cocher Autoriser nulls pour la colonne que vous voulez changer.
  • dans L'onglet Propriétés de la colonne, étendre la propriété Spécification D'identité.
  • cliquez sur la case de la grille l'identité est la propriété de l'enfant et choisissez Oui dans la liste déroulante.
  • Type A valeur dans la cellule D'identité. Cette valeur sera attribuée à la première ligne du tableau. La valeur 1 sera attribuée par défaut.

c'est cela, et cela a fonctionné pour moi

2
répondu Ken.Fukizi 2017-07-31 16:47:36

si l'affiche originale voulait en fait mettre une colonne existante pour être une PRIMARY KEY pour la table et n'avait pas besoin que la colonne soit une IDENTITY colonne (deux choses différentes) alors cela peut être fait via t-SQL avec:

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

notez la parenthèse autour du nom de la colonne après l'option PRIMARY KEY .

bien que ce poste est vieux et je fais une hypothèse sur les besoins des demandeurs, je me suis senti ce supplémentaire l'information pourrait être utile pour les utilisateurs rencontrant ce fil que je crois que la conversation pourrait conduire à croire qu'une colonne existante ne peut pas être configuré pour être une clé primaire sans l'ajout d'une nouvelle colonne qui serait incorrect.

1
répondu A. Omalley 2011-11-23 10:22:04

selon mon état actuel, je suis cette approche. Je veux donner l'identité à une table primaire après les données insérées par script.

comme je veux ajouter l'identité, donc il commence toujours de 1 à fin de Compte d'enregistrement 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 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 la clé primaire à la table existante

1
répondu Ajay2707 2017-05-23 12:10:47

Je ne crois pas qu'on puisse modifier une colonne existante pour qu'elle soit une colonne d'identité à l'aide de tsql. Cependant, vous pouvez le faire par l'Entreprise Gestionnaire de la vue de conception.

vous pouvez aussi créer une nouvelle ligne comme colonne identité, laisser tomber l'ancienne colonne, puis renommer votre nouvelle colonne.

ALTER TABLE FooTable
ADD BarColumn INT IDENTITY(1, 1)
               NOT NULL
               PRIMARY KEY CLUSTERED
0
répondu William Edmondson 2009-06-26 13:56:58

fondamentalement, il y a quatre étapes logiques.

  1. créer une nouvelle colonne identité. Allumez Insérer Identité de cette nouvelle colonne.

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

  3. désactiver L'indication de la nouvelle colonne.

  4. Drop votre colonne source et renommez la nouvelle colonne par le nom de la colonne source.

il peut y avoir d'autres complexités comme travailler sur plusieurs serveurs, etc.

, Veuillez consulter l'article suivant pour les étapes (à l'aide de ssms et T-sql). Ces étapes sont destinées aux débutants avec moins de prise sur 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
répondu Shivalik Chakravarty 2014-04-19 06:51:31

génère un script pour toutes les tables avec la clé primaire = bigint qui n'ont pas de jeu d'identité; ceci retournera une liste des 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
répondu Kyle Gibbar 2014-10-29 15:09:55