Как проверить, существует ли столбец в таблице SQL Server?


1,495

Мне нужно добавить конкретный столбец, если он не существует. У меня есть что-то вроде этого, но он всегда возвращает ложь:

IF EXISTS(SELECT * 
      FROM INFORMATION_SCHEMA.COLUMNS 
      WHERE TABLE_NAME = 'myTableName' 
       AND COLUMN_NAME = 'myColumnName') 

Как я могу проверить, если столбец существует в таблице базы данных SQL Server?

+9

Я действительно не думаю, что с кодом в q нет ничего плохого uestion: Прекрасно работает для меня в 2008 R2. (Может быть, вы использовали его в неправильной базе данных? Возможно, ваша база данных чувствительна к регистру, и у вас не было права в строках myTableName/myColumnName? Этот тип запроса кажется более гибким, чем решение COL_LENGTH: я могу для запуска его с другой базой данных и даже по ссылке базы данных путем соответствующего префикса «INFORMATION_SCHEMA». Не удалось увидеть, как это сделать с помощью функции метаданных COL_LENGTH. 13 июн. 132013-06-13 14:57:02

+2

@mwardm - 'COL_LENGTH ('AdventureWorks2012.HumanResources.Department' «ModifiedDate») 'отлично работает. 12 сен. 132013-09-12 16:38:03

+4

Маленькая связанная подсказка: если вы хотите обновить столбец сразу после добавления столбца (я считаю, что многие пользователи искали эту статью для этой цели), вы могли бы использовать' EXEC sp_executesql' с сформированным 'UPDATE' 16 апр. 152015-04-16 15:02:13

  0

Реальный ответ: вы должны добавить базу данных, которую вы проверяете, поэтому она 'FROM [YourDatabase] .INFORMATION_SCHEMA.COLUMNS' 25 июн. 152015-06-25 22:35:00

1,636

SQL Server 2005 года: версия

IF EXISTS(SELECT 1 FROM sys.columns 
      WHERE Name = N'columnName' 
      AND Object_ID = Object_ID(N'schemaName.tableName')) 
BEGIN 
    -- Column Exists 
END 

Мартина Смита короче:

IF COL_LENGTH('schemaName.tableName', 'columnName') IS NOT NULL 
BEGIN 
    -- Column Exists 
END 
+292

Или вы можете сохранить некоторую типизацию и использовать 'IF COL_LENGTH ('tableName', 'columnName') IS NOT NULL' 20 мар. 112011-03-20 14:54:49

+19

@Mitch - согласно документам он вернет' NULL', если у пользователя нет разрешений для просмотра метаданные, но 'sys.columns' также проверяет доступ пользователей. 21 мар. 112011-03-21 00:26:52

+9

@MitchWheat -> Я бы сказал вместо select * inside if exists, я бы использовал select 1 из sys.columns, так что он просто возвращает скалярное значение, а не набор строк. твои мысли ? 19 ноя. 122012-11-19 05:00:42

  0

Зачем использовать * и извлекать все столбцы в запросе, используя «имя» или «1», даст лучшую производительность, поэтому внутренний запрос может быть выбран * из sys.columns, где Name = N'columnName 'и Object_ID = Object_ID (N 'tableName') 03 дек. 132013-12-03 11:31:29

  0

Обратите внимание, что если все не сбрасывается в схему dbo, которая также должна быть частью запроса. Я склонен использовать таблицы information_schema в донкихотской попытке портативного SQL (это также более простой выбор). 08 авг. 142014-08-08 15:53:39

+26

Это может быть очевидно, но если таблица находится в схеме, отличной от dbo, вы должны написать схему как часть имени: '... AND [object_id] = OBJECT_ID (N'schemaName.tableName '...) 'не делает этого, заставит запрос возвращать никакие строки, даже если столбец существует. 20 янв. 152015-01-20 14:00:51


58

Попробуйте это ...

IF NOT EXISTS(
    SELECT TOP 1 1 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE 
    [TABLE_NAME] = 'Employees' 
    AND [COLUMN_NAME] = 'EmployeeID') 
BEGIN 
    ALTER TABLE [Employees] 
    ADD [EmployeeID] INT NULL 
END 
+3

T его метод также работает с SQL CE, в то время как некоторые из других упомянутых методов этого не делают. 14 ноя. 132013-11-14 20:00:24

+5

Вы можете использовать 'SELECT 1' вместо' SELECT TOP 1 1';;). 15 июн. 152015-06-15 12:22:42

+2

В выражении 'EXISTS' SQL автоматически оптимизирует столбцы (так же, как' count (*) '), поэтому' SELECT * 'будет достаточно. 01 мар. 162016-03-01 19:49:28


121

Tweak ниже, чтобы удовлетворить ваши конкретные требования:

if not exists (select 
        column_name 
       from 
        INFORMATION_SCHEMA.columns 
       where 
        table_name = 'MyTable' 
        and column_name = 'MyColumn') 
    alter table MyTable add MyColumn int 

Редактировать, чтобы иметь дело с редактированием на вопрос: Это должно работать - внимательно посмотреть над вашим кодом за глупые ошибки; вы запрашиваете INFORMATION_SCHEMA в той же базе данных, к которой применяется ваша вставка? У вас есть опечатка в имени таблицы/столбца в любом выражении?

+3

Я только что узнал, что добавление TABLE_SCHEMA = 'mySchema' после того, как предложение исправляет проблему. 25 сен. 082008-09-25 17:01:16

+7

-1: не отвечает на вопрос OP, добавляет новую информацию о том, как добавить новый столбец, несмотря на то, что OP не спрашивает об этом вообще, не рассматривает комментарий OP. 02 ноя. 112011-11-02 11:46:58


26

Сначала проверьте, если комбинация table/column (id/name) существует в dbo.syscolumns (внутреннюю таблицу SQL Server, который содержит определения полей), и если не выдавать соответствующий ALTER TABLE запрос, чтобы добавить его. Например:

IF NOT EXISTS (SELECT * 
      FROM syscolumns 
      WHERE id = OBJECT_ID('Client') 
        AND name = 'Name') 
ALTER TABLE Client 
ADD Name VARCHAR(64) NULL 

37

Вы можете использовать представление системы информации схемы, чтобы узнать почти все о таблицах вы заинтересованы в:

SELECT * 
    FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'yourTableName' 
ORDER BY ORDINAL_POSITION 

Вы можете также опрашивать представления, хранимые процедуры и довольно что-нибудь о базе данных, использующей представления Information_schema.


25

Try что-то вроде:

CREATE FUNCTION ColumnExists(@TableName varchar(100), @ColumnName varchar(100)) 
RETURNS varchar(1) AS 
BEGIN 
DECLARE @Result varchar(1); 
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = @TableName AND COLUMN_NAME = @ColumnName) 
BEGIN 
    SET @Result = 'T' 
END 
ELSE 
BEGIN 
    SET @Result = 'F' 
END 
RETURN @Result; 
END 
GO 

GRANT EXECUTE ON [ColumnExists] TO [whoever] 
GO 

Затем использовать его как это:

IF ColumnExists('xxx', 'yyyy') = 'F' 
BEGIN 
    ALTER TABLE xxx 
    ADD yyyyy varChar(10) NOT NULL 
END 
GO 

Он должен работать как на SQL Server 2000 & SQL Server 2005. Не уверен, что SQL Server 2008, но дон почему бы и нет.


42

Я предпочитаю INFORMATION_SCHEMA.COLUMNS над столом системы, поскольку Microsoft не гарантирует сохранение системных таблиц между версиями , Например, dbo.syscolumns все еще работает в SQL 2008, но он устарел и может быть удален в любое время в будущем.

+5

[«Представления INFORMATION_SCHEMA могут быть неполными, поскольку они не обновляются для всех новых функций»] (http://msdn.microsoft.com/en-us/library/ms186224.aspx) 26 фев. 132013-02-26 15:45:45

+3

Ну да, это само собой разумеется, так как ' Представления INFORMATION_SCHEMA' содержат только метаданные стандарта ANSI. Однако этого достаточно для теста существования. 26 фев. 132013-02-26 17:15:46

+1

Microsoft говорит: «В будущих выпусках SQL Server Microsoft может расширить определение любого представления системного каталога, добавив столбцы в конец списка столбцов. Мы рекомендуем не использовать синтаксис SELECT * FROM sys.catalog_view_name в производственном коде, потому что число возвращенных столбцов может изменить и разорвать ваше приложение ». Это означает, что они не будут удалять столбцы или изменять их порядок. Это достаточно хорошая обратная совместимость для всех, кроме случаев с краями. 12 июл. 132013-07-12 21:26:57


22
declare @myColumn as nvarchar(128) 
set @myColumn = 'myColumn' 
if not exists (
    select 1 
    from information_schema.columns columns 
    where columns.table_catalog = 'myDatabase' 
     and columns.table_schema = 'mySchema' 
     and columns.table_name  = 'myTable' 
     and columns.column_name  = @myColumn 
    ) 
begin 
    exec('alter table myDatabase.mySchema.myTable add' 
    +' ['[email protected]+'] bigint  null') 
end 

817

более краткая версия

IF COL_LENGTH('table_name','column_name') IS NULL 
BEGIN 
/*Column does not exist or caller does not have permission to view the object*/ 
END 

Дело о разрешениях на просмотр метаданных относится ко всем ответам не только этим.

Обратите внимание, что имя первой таблицы параметров до COL_LENGTH может быть в формате одного, двух или трех частей, если требуется.

Пример ссылки на таблицу в другой базе данных

COL_LENGTH('AdventureWorks2012.HumanResources.Department','ModifiedDate') 

Одно различие с этим ответом по сравнению с использованием мнения метаданных является то, что функции метаданных, таких как COL_LENGTH всегда возвращать только данные о совершенных изменений независимо от изоляции уровень в действии.

+9

Это менее читаемо, чем некоторые другие ответы, вероятно, почему он не так высоко оценен. 30 ноя. 112011-11-30 22:09:36

+27

@Bill - Меньше можно прочитать, каким образом? Выглядит хорошо в Firefox. Этот ответ был опубликован более чем на 2 года позже принятого, что объясняет рейтинг ИМО. Если вы имели в виду менее ясно, что это проверка существования, этот тип идиомы довольно распространен в SQL Server. например используя 'IF OBJECT_ID ('TableName', 'U') IS NULL' для проверки существования объекта или' DB_ID ('foo') 'для проверки существования базы данных. 30 ноя. 112011-11-30 22:31:28

+45

@MartinSmith Я уверен, что он имел в виду менее читаемый, потому что, если вы не знали эту идиому, и вы унаследовали этот код от кого-то другого, вы не сразу поймете, что делает код. Вроде как писать 'x >> 2' вместо' x/4' в C++. Более подробный код ('if exists (select column_name from information_schema ...)') занимает гораздо больше места, но никто никогда не поцарапал бы голову, пытаясь понять, что он делает. 20 авг. 132013-08-20 16:49:02

+13

Кроме того, это более быстрое решение. Доступ к просмотрам 'INFORMATION_SCHEMA' или' sys.columns' удаляет диск, а 'COL_LENGTH' использует метаданные метаданных в кэше. 13 янв. 142014-01-13 08:49:11

+6

Это, вероятно, не самый высоко оцененный ответ, потому что ему дали 2,5 года после другого. Вот почему я всегда проверяю даты при сравнении рейтингов с двумя ответами. Требуется намного больше времени, чтобы преодолеть ответ, который был дан гораздо раньше. ;) 28 фев. 142014-02-28 19:35:42

+1

Решение «_Less readable_»: 'IF COL_LENGTH ('Incidente_Incidente', 'Id_NC_I') IS NULL/* <--- Эта строка проверяет, существует ли столбец в таблице SQL Server * /';) 28 май. 142014-05-28 12:53:17

+2

Требуется решение select дополнительная проверка столбца для сценария схемы. col_length может использоваться 'col_length ('schema.table', 'column')'. 08 сен. 142014-09-08 13:08:22

+1

@PasiSavolainen, и он также принимает три названия. 'Db_name.schema_name.table_name'. Я отредактирую свой ответ, чтобы включить это явно как три upvotes [на этот комментарий] (http://stackoverflow.com/questions/133031/how-to-check-if-column-exists-in-sql-server- table # comment24720735_133031) указывает, что не каждый реализует ... 08 сен. 142014-09-08 19:03:07

  0

@Kip Это правда, но по моему опыту проблема смягчается кодом, который неизбежно следует: 'ALTER TABLE my_table ADD column_name' :) То же самое с методом' OBJECT_ID' , Если этот код * не использует это использование функции, возможно, некоторые комментарии (или расширенный синтаксис в исходном ответе) оправданы. 29 янв. 152015-01-29 15:26:18

  0

Просто нужно использовать это через весь наш флот - я могу подтвердить, что это работает с SQL 2000 по 2014 год. 01 дек. 152015-12-01 02:07:37


20

Это работает для меня в SQL 2000:

IF EXISTS 
(
    SELECT * 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE table_name = 'table_name' 
    AND column_name = 'column_name' 
) 
BEGIN 
... 
END 

19

Попробуйте

SELECT COLUMNS.* 
FROM INFORMATION_SCHEMA.COLUMNS COLUMNS, 
     INFORMATION_SCHEMA.TABLES TABLES 
WHERE COLUMNS.TABLE_NAME = TABLES.TABLE_NAME 
     AND Upper(COLUMNS.COLUMN_NAME) = Upper('column_name') 
  0

Вам не нужна 'INFORMATION_SCHEMA.TABLES', и вы не фильтруете столбцы для определенной таблицы, поэтому она иногда возвращается более одной строки для одинаковых имен столбцов в отдельных таблицах;). 15 июн. 152015-06-15 12:34:53


16

мне нужно похож на SQL SERVER 2000 и, как @Mitch указывает, что это работает только INM 2005+.

Если это поможет кто-то другой, это то, что работает для меня в конце концов:

if exists (
    select * 
    from 
     sysobjects, syscolumns 
    where 
     sysobjects.id = syscolumns.id 
     and sysobjects.name = 'table' 
     and syscolumns.name = 'column') 

21

Хороший друг и мой коллега показал мне, как вы можете также использовать IF блок с функциями SQL OBJECT_ID и COLUMNPROPERTY в SQL SERVER 2005+ для проверки столбца. Вы можете использовать что-то подобное следующему:

You can see for yourself here

IF (OBJECT_ID(N'[dbo].[myTable]') IS NOT NULL AND 
    COLUMNPROPERTY(OBJECT_ID(N'[dbo].[myTable]'), 'ThisColumnDoesNotExist', 'ColumnId') IS NULL) 
BEGIN 
    SELECT 'Column does not exist -- You can add TSQL to add the column here' 
END 
  0

И, конечно, если вы уверены, что таблица существует, вы можете оставить первую часть условия и проверить только «COLUMNPROPERTY». 12 дек. 142014-12-12 12:52:15


9
select distinct object_name(sc.id) 
from syscolumns sc,sysobjects so 
where sc.name like '%col_name%' and so.type='U' 

10
IF NOT EXISTS(SELECT NULL 
      FROM INFORMATION_SCHEMA.COLUMNS 
      WHERE table_name = 'tablename' 
      AND table_schema = 'db_name' 
      AND column_name = 'columnname') THEN 

    ALTER TABLE `TableName` ADD `ColumnName` int(1) NOT NULL default '0'; 

END IF; 
+1

Я думаю, вы имели в виду table_schema = 'schema_name'. 28 июл. 142014-07-28 13:17:48


12
if exists (select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='<table_name>' and COLUMN_NAME='<column_name>') 
    begin 
    print 'Column you have specified exists' 
    end 
else 
    begin 
    print 'Column does not exists' 
    end 

0

еще один вариант ...

SELECT Count(*) AS existFlag FROM sys.columns 
WHERE [name] = N'ColumnName' AND [object_id] = OBJECT_ID(N'TableName') 

9

A версия временную таблицу из accepted answer :

if (exists(select 1 
      from tempdb.sys.columns 
      where Name = 'columnName' 
       and Object_ID = object_id('tempdb..#tableName'))) 
begin 
... 
end 
  0

Как это отличается от принятого ответа? Будет ли временная таблица не работать в принятом ответе? 08 янв. 152015-01-08 01:24:14

  0

Исправить. Принимаемый ответ не работает для временных таблиц, потому что «sys.columns» должен быть указан как «tempdb.sys.columns», а имя таблицы должно быть продолжено «tempdb ..». 08 янв. 152015-01-08 20:08:26


4

Ответы на пшеницу хорошие, но предполагается, Для того, чтобы сделать его безопасным для этого условия использовать это ...

select * 
from Information_Schema.Columns 
where Table_Catalog = 'DatabaseName' 
    and Table_Schema = 'SchemaName' 
    and Table_Name = 'TableName' 
    and Column_Name = 'ColumnName' 

-10

Я бы лучше пойти на

IF EXISTS(SELECT * 
      FROM INFORMATION_SCHEMA.COLUMNS 
      WHERE TABLE_NAME = 'myTableName' 
       AND COLUMN_NAME = 'myColumnName') 

Эта проверка, существует ли таблица, а также столбец в частности таблица существует. Пробовал только на MYSQL, хотя, не пробовал его для других баз данных.

Немного отличается в базе данных Oracle.

Select count(*) 
    from user_tab_cols 
    where column_name = 'myColumnName' 
     and table_name = 'myTableName'; 

Это вернет вам либо 1, если столбец существует в конкретной таблице, 0, если нет. Тем не менее, больше PL/SQL.


2

Существует несколько способов проверить наличие столбца. Я настоятельно рекомендую использовать INFORMATION_SCHEMA.COLUMNS, поскольку он создан для взаимодействия с пользователем. Рассмотрим следующие таблицы:

sys.objects 
sys.columns 

и даже некоторые другие методы доступа, доступные для проверки системного каталога.

Кроме того, нет необходимости использовать SELECT *, просто проверить его значение NULL

IF EXISTS(
      SELECT NULL 
      FROM INFORMATION_SCHEMA.COLUMNS 
      WHERE 
      TABLE_NAME = 'myTableName' 
      AND COLUMN_NAME = 'myColumnName' 
     ) 

21

Для тех, кто проверяет существование столбца уронить его.

В SQL Server, 2016 вы можете использовать новые заявления Умереть вместо больших IF оберток

ALTER TABLE Table_name DROP COLUMN IF EXISTS Column_name 

-4

Используйте этот запрос:

IF EXISTS(SELECT Statement) 
    BEGIN 
    Code 
    END 

    ELSE 

    BEGIN 
    Code 
    END 

    OR 

    IF NOT EXISTS(Select Statement) 
    Begin 
    code 
    End 

    ELSE 
    Begin 
    code 
    End 

Таким образом, вы можете использовать условие в SQL.

Надеюсь, это поможет.

+2

Как это улучшает или предлагает альтернативу принятому ответу? 04 май. 162016-05-04 12:52:25

  0

@ Мухаммад, я думал, что если я дам скелет как IF EXISTS, так и ЕСЛИ НЕ СУЩЕСТВУЕТ пользователю, это может быть полезно для них. Вот и все. У меня не было другой идеи, чем принятый ответ. 04 май. 162016-05-04 13:30:37


-3

Коммерческий продукт, с которым я работаю, использует запрос, аналогичный приведенному ниже, проверяя наличие всех необходимых столбцов одновременно. Запрос и, в частности, список столбцов создается в программном обеспечении.

SELECT COUNT(Column1+Column2+...+ColumnN) 
FROM [Tablename] 
WHERE ID=NULL 

Запрос представлен на сервер с помощью программного обеспечения и связи ODBC к базе данных и запустить нашу программу на C++ внутри обработчика исключений примерки поймать.

Если запрос работает нормально, столбцы существуют. Если запрос завершается с ошибкой, выполняются дополнительные запросы, а отсутствующие столбцы создаются и т. Д., Поэтому наше программное обеспечение всегда имеет таблицы и столбцы, которые необходимо запустить правильно. Старые базы данных обновляются, чтобы добавить столбцы, которые они отсутствуют.

Решение отличается от многих решений выше, поскольку оно работает с программным обеспечением и может обрабатывать серверы баз данных, которые предшествуют определенным таблицам систем SQL Server и его функциям, например INFORMATION_SCHEMA.COLUMNS, sys.columns и object_id(), некоторые из которых являются специфическими для поставщика в любом случае, и не предоставлять общее решение на всех серверах Microsoft SQL и Adobe MySQL и т. д.

Если ваши запросы выполняются вашим собственным программным обеспечением и подключением ODBC к SQL Server, и вы хотите, чтобы они запускались с базами данных, отличными от SQL Server тоже, тогда этот подход заслуживает рассмотрения.

Это сообщение неоднократно проголосовало. Я знаю, что это не решение для большинства людей, поскольку оно предназначено для интеграции в программное обеспечение, и я знаю, что не модно предоставлять что-то, что работает с устаревшими системами, а не предполагать и полагаться на современные технологии. Идея try-catch является уродливой и использование идентификатора WHERE ID = NULL для возврата одного значения независимо от фактического содержимого таблицы также не является прямым. Но, несмотря на подавляющие голоса, я оставляю это здесь, если это кому-то помогает.


2

Вот простой скрипт, который я использую для управления добавлением столбцов в базе данных:

IF NOT EXISTS (
     SELECT * 
     FROM sys.Columns 
     WHERE Name = N'QbId' 
      AND Object_Id = Object_Id(N'Driver') 
     ) 
BEGIN 
    ALTER TABLE Driver ADD QbId NVARCHAR(20) NULL 
END 
ELSE 
BEGIN 
    PRINT 'QbId is already added on Driver' 
END 

В этом примере Name является ColumnName быть добавлен и Object_Id является TableName


3

Один из наиболее простым и понятным решением является:

IF COL_LENGTH('Table_Name','Column_Name') IS NULL 
BEGIN 
    -- Column Not Exists, implement your logic 
END 
ELSE 
BEGIN 
    -- Column Exists, implement your logic 
END