Ajouter une colonne à une table, si elle n'existe pas déjà

195

Je veux écrire une requête pour MS SQL Server qui ajoute une colonne dans une table. Mais je ne veux aucun affichage d'erreur lorsque j'exécute / exécute la requête suivante.

J'utilise ce type de requête pour ajouter une table ...

IF EXISTS (
       SELECT *
       FROM   sys.objects
       WHERE  OBJECT_ID = OBJECT_ID(N'[dbo].[Person]')
              AND TYPE IN (N'U')
   )

Mais je ne sais pas comment écrire cette requête pour une colonne.

Tavousi
la source
Vous devriez utiliser à la sys.tablesplace du "générique" sys.objects- alors vous n'avez pas à spécifier le type explicitement (c'est évident du sys.tablesdéjà ....)
marc_s
COL_LENGTH Alternative fonctionne uniquement à partir de SQL-Server 2008, mais cela fonctionne.
Paul-Henri
@MartinSmith PAS un double de cela. Votre lien est un moyen possible de le résoudre (et en fait, c'est le moyen recommandé, en ce moment). Mais la question est en fait différente et d'autres solutions pourraient être disponibles (par exemple si SQL ajoute une IF NOT EXISTSclause à la ADD COLUMNsyntaxe)
Brondahl
@Brondahl - car la question a survécu au cours des 8,5 ans depuis la publication du commentaire auquel vous répondez n'a probablement pas besoin de paniquer. Pour le moment, toutes les réponses ici sont essentiellement des dupes de celles du Q lié
Martin Smith

Réponses:

226

Vous pouvez utiliser une construction similaire en utilisant la sys.columnstable io sys.objects.

IF NOT EXISTS (
  SELECT * 
  FROM   sys.columns 
  WHERE  object_id = OBJECT_ID(N'[dbo].[Person]') 
         AND name = 'ColumnName'
)
Lieven Keersmaekers
la source
43
Notez que dans ce cas, vous souhaitez utiliser IF NOT EXISTS dans votre code réel.
Nat
2
Pour une requête optimisée, vous pouvez utiliser le top 1 avec l'instruction select
Banketeshvar Narayan
12
@BanketeshvarNarayan c'est incorrect. Les plans d'exécution des sous-requêtes dans une EXISTSclause sont identiques. Des choses comme SELECT 1ou SELECT TOP 1sont inutiles. La EXISTSclause elle-même indique à l'optimiseur de requêtes de n'effectuer que les lectures minimales nécessaires pour évaluer le EXISTS... au moins dans SQL Server. D'autres moteurs de base de données peuvent avoir un optimiseur de requêtes plus ou moins efficace.
Kenneth Cochran
10
@BanketeshvarNarayan Si vous optimisez vos ADD Columnrequêtes ... vous devez les exécuter trop souvent!
Fenton
1
@ user391339 - J'ai publié une construction similaire à celle publiée par OP, mais oui, si vous voulez prendre des mesures si la colonne n'existe pas , l'instruction serait IF NOT EXISTS. Je ne ressens pas vraiment le besoin de modifier la réponse pour cela, mais n'hésitez pas à modifier vous-même si vous pensez que c'est une amélioration.
Lieven Keersmaekers
98
IF COL_LENGTH('table_name', 'column_name') IS NULL
BEGIN
    ALTER TABLE table_name
    ADD [column_name] INT
END
SPL
la source
1
J'ai essayé de faire celui-ci mais cela renvoie une erreur indiquant que la fonction COL_LENGTH n'existe pas.
ThEpRoGrAmMiNgNoOb
3
Requiert SQL Server 2008+
Robert Brown
7
Petit ajout - il ne faut pas utiliser de crochets dans le nom de la colonne, car COL_LENGTH('table_name', '[column_name]')il renvoie toujours null dans SQL Server 2016 ( COL_LENGTH('[table_name]', 'column_name') works as expected).
stop-cran
34

Une autre alternative. Je préfère cette approche car elle est moins écrite mais les deux accomplissent la même chose.

IF COLUMNPROPERTY(OBJECT_ID('dbo.Person'), 'ColumnName', 'ColumnId') IS NULL
BEGIN
    ALTER TABLE Person 
    ADD ColumnName VARCHAR(MAX) NOT NULL
END

J'ai également remarqué que le vôtre cherchait où la table existe qui est évidemment juste ceci

 if COLUMNPROPERTY( OBJECT_ID('dbo.Person'),'ColumnName','ColumnId') is not null
JStead
la source
2
Je l'aime. Je pense que la meilleure partie de la publication ici est de trouver des gemmes comme celle-ci.
JStead
4
Qu'est-ce que «ColumnId»?
Marius Stănescu
'ColumnId' est le nom de la propriété de colonne que vous comparez. Vous auriez probablement pu utiliser n'importe quel nom de propriété existant sur une colonne, tel que name, etc.
Jacques Bosch
6

Voici une autre variante qui a fonctionné pour moi.

IF NOT EXISTS (SELECT 1
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE upper(TABLE_NAME) = 'TABLENAME'
        AND upper(COLUMN_NAME) = 'COLUMNNAME')
BEGIN
    ALTER TABLE [dbo].[Person] ADD Column
END
GO

MODIFIER: Notez que les INFORMATION_SCHEMAvues ne sont pas toujours mises à jour, utilisez à la SYS.COLUMNSplace:

IF NOT EXISTS (SELECT 1 FROM SYS.COLUMNS....

Adil H. Raza
la source
0
IF NOT EXISTS (SELECT 1  FROM SYS.COLUMNS WHERE  
OBJECT_ID = OBJECT_ID(N'[dbo].[Person]') AND name = 'DateOfBirth')
BEGIN
ALTER TABLE [dbo].[Person] ADD DateOfBirth DATETIME
END
Code d'abord
la source
0
IF NOT EXISTS (SELECT * FROM syscolumns
  WHERE ID=OBJECT_ID('[db].[Employee]') AND NAME='EmpName')
  ALTER TABLE [db].[Employee]
  ADD [EmpName] VARCHAR(10)
GO

J'espère que cela aiderait. Plus d'informations

ShaileshDev
la source
Cela a fonctionné pour moi sur SqlServer 2000 alors que la réponse acceptée n'a pas fonctionné. Les vues sys. * Semblent avoir été ajoutées quelque part autour de SqlServer 2005, cf. docs.microsoft.com/en-us/sql/relational-databases/…
ZeRemz
0

Lors de la recherche d'une colonne dans une autre base de données, vous pouvez simplement inclure le nom de la base de données:

IF NOT EXISTS (
  SELECT * 
  FROM   DatabaseName.sys.columns 
  WHERE  object_id = OBJECT_ID(N'[DatabaseName].[dbo].[TableName]') 
         AND name = 'ColumnName'
)
Ezra
la source