Проверьте, существует ли таблица в SQL Server


1143

Я хотел бы, чтобы это было окончательным обсуждением того, как проверить, существует ли таблица в SQL Server 2000/2005 с использованием операторов SQL.

Когда вы Google для ответа, вы получите так много разных ответов. Есть ли официальный / обратный и прямой совместимый способ сделать это?

Вот два возможных способа сделать это. Какой из двух является стандартным / лучшим способом сделать это?

Первый способ:

IF EXISTS (SELECT 1 
           FROM INFORMATION_SCHEMA.TABLES 
           WHERE TABLE_TYPE='BASE TABLE' 
           AND TABLE_NAME='mytablename') 
   SELECT 1 AS res ELSE SELECT 0 AS res;

Второй способ:

IF OBJECT_ID (N'mytablename', N'U') IS NOT NULL 
   SELECT 1 AS res ELSE SELECT 0 AS res;

MySQL обеспечивает простой

SHOW TABLES LIKE '%tablename%'; 

заявление. Я ищу что-то подобное.


1
Почему лучше использовать INFORMATION_SCHEMA.TABLES вместо sys.tables, а затем отфильтровать по имени, может быть, добавить проверку значения type_desc?
DanteTheSmith

Ответы:


1332

Для таких запросов всегда лучше использовать INFORMATION_SCHEMAпредставление. Эти представления (в основном) являются стандартными для многих различных баз данных и редко меняются от версии к версии.

Чтобы проверить, существует ли таблица, используйте:

IF (EXISTS (SELECT * 
                 FROM INFORMATION_SCHEMA.TABLES 
                 WHERE TABLE_SCHEMA = 'TheSchema' 
                 AND  TABLE_NAME = 'TheTable'))
BEGIN
    --Do Stuff
END

12
Работает отлично! В T-SQL (в ответ на оригинальный постер) это TABLE_SCHEMA, а не SCHEMA_NAME. Спасибо за совет.
Николай Пясецкий

10
Учитывая, что одно только имя объекта (то есть без схемы) не гарантируется быть уникальным, не существует 100% надежного способа сделать это. Если вы работаете с БД, которая не имеет конфликтов имен в разных схемах, то просто пропустите TABLE_SCHEMA = 'TheSchema' "будет работать очень хорошо.
Акмад

26
Чтобы проверить временную таблицу, мы должны запросить базу данных tempdb и использовать оператор LIKE для имени таблицыSELECT * FROM tempdb.INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'TheSchema' AND TABLE_NAME LIKE '#TheTable%'
Pierre-Alain Vigeant

4
Приведенный ниже ответ, в котором используется функция OBJECT_ID, работает правильно в отношении временных таблиц подключения - stackoverflow.com/a/2155299/16147
Рич Руссо,

4
@akmad Компилятор SQL-запросов проверит таблицу перед запуском запроса и завершится ошибкой даже перед запуском.
Марк К

279

Также обратите внимание, что если по какой-либо причине вам нужно проверить временную таблицу, вы можете сделать это:

if OBJECT_ID('tempdb..#test') is not null
 --- temp table exists

11
Использование этого метода, похоже, учитывает природу подключения временных таблиц. Ранее опубликованный запрос INFORMATION_SCHEMA будет возвращать строки независимо от соединения, создавшего таблицу.
Рич Руссо

238

Мы всегда используем OBJECT_IDстиль, насколько я помню

IF OBJECT_ID('*objectName*', 'U') IS NOT NULL 

16
Я считаю, что это будет быстро, хотя и не очень портативно. Представления информационной схемы гарантированно существуют в любой СУБД, поддерживающей стандарт. Кроме того, обычный OBJECT_ID не гарантирует, что объект является таблицей.
Джо Пинеда

9
Спасибо, Джо, мне было интересно, почему вы используете OBJECT_ID против INFORMATION_SCHEMA.TABLES против sys.tables. Указание на то, что INFORMATION_SCHEMA является частью стандарта, в значительной степени отвечает на этот вопрос. Кстати, забавно, что один из наших экспертов по базам данных, который я собирался задать этому вопросу, имеет ту же фамилию, что и вы, должна быть хорошей фамилией для баз данных.
Apeiron

24
@JoePineda: Тогда вы используете случай, OBJECT_ID('TableName', 'U')чтобы гарантировать, что объект является таблицей.
Аллон Гуралнек

1
@AllonGuralnek, так что, вместо того, чтобы следовать простому и переносимому стандарту, добавить дополнительную загадочную информацию?
определяет

22
@DustinFineout: вопрос был помечен как tsql , поэтому переносимость не так важна . В общем, я сталкивался с очень немногими действительно переносимыми кодовыми базами, и если краткость оценивается, то она наверняка превосходит написание этого IF EXISTSзапроса из принятого ответа снова и снова. Кроме того, все загадочно, пока вы не прочитаете документацию, особенно в T-SQL (или любом другом варианте, на самом деле).
Аллон Гуралнек

132

Пожалуйста, смотрите ниже подходы,

Подход 1: Использование представления INFORMATION_SCHEMA.TABLES

Мы можем написать запрос, как показано ниже, чтобы проверить, существует ли таблица клиентов в текущей базе данных.

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'Customers')
BEGIN
    PRINT 'Table Exists'
END

Подход 2: Использование функции OBJECT_ID ()

Мы можем использовать функцию OBJECT_ID (), как показано ниже, чтобы проверить, существует ли таблица клиентов в текущей базе данных.

IF OBJECT_ID(N'dbo.Customers', N'U') IS NOT NULL
BEGIN
    PRINT 'Table Exists'
END

Подход 3. Использование каталога sys.Objects

Мы можем использовать представление каталога Sys.Objects, чтобы проверить существование таблицы, как показано ниже:

IF EXISTS(SELECT 1 FROM sys.Objects WHERE  Object_id = OBJECT_ID(N'dbo.Customers') AND Type = N'U')
BEGIN
   PRINT 'Table Exists'
END

Подход 4. Использование каталога sys.Tables

Мы можем использовать представление каталога Sys.Tables, чтобы проверить существование таблицы, как показано ниже:

 IF EXISTS(SELECT 1 FROM sys.Tables WHERE  Name = N'Customers' AND Type = N'U')
 BEGIN
      PRINT 'Table Exists'
 END

Подход 5. Избегайте использования системной таблицы sys.sysobjects.

Мы должны избегать использования системной таблицы sys.sysobjects напрямую, прямой доступ к ней не рекомендуется в некоторых будущих версиях Sql Server. Что касается ссылки Microsoft BOL, Microsoft предлагает использовать каталоги sys.objects / sys.tables вместо системной таблицы sys.sysobjects напрямую.

  IF EXISTS(SELECT name FROM sys.sysobjects WHERE Name = N'Customers' AND xtype = N'U')
  BEGIN
     PRINT 'Table Exists'
  END

по ссылке : http://sqlhints.com/2014/04/13/how-to-check-if-a-table-exists-in-sql-server/



26

Просто хотел бы упомянуть одну ситуацию, когда было бы немного проще использовать OBJECT_IDметод. Представления INFORMATION_SCHEMA- это объекты в каждой базе данных.

Представления информационной схемы определены в специальной схеме с именем INFORMATION_SCHEMA. Эта схема содержится в каждой базе данных.

https://msdn.microsoft.com/en-us/library/ms186778.aspx

Поэтому все таблицы, к которым вы обращаетесь с помощью

IF EXISTS (SELECT 1 
           FROM [database].INFORMATION_SCHEMA.TABLES 
           WHERE TABLE_TYPE='BASE TABLE' 
           AND TABLE_NAME='mytablename') 
   SELECT 1 AS res ELSE SELECT 0 AS res;

будет отражать только то, что в [database]. Если вы хотите проверить, существуют ли таблицы в другой базе данных, без динамического изменения [database]каждый раз, OBJECT_IDэто позволит вам сделать это «из коробки». бывший

IF OBJECT_ID (N'db1.schema.table1', N'U') IS NOT NULL 
   SELECT 1 AS res ELSE SELECT 0 AS res;

работает так же хорошо, как

IF OBJECT_ID (N'db2.schema.table1', N'U') IS NOT NULL 
   SELECT 1 AS res ELSE SELECT 0 AS res;

SQL SERVER 2016 Редактировать :

Начиная с 2016 года Microsoft упростила возможность проверять несуществующие объекты перед удалением, добавляя if existsключевые слова в dropоператоры. Например,

drop table if exists mytablename

будет делать то же самое, что и OBJECT_ID/INFORMATION_SCHEMA wrappers, в 1 строке кода.

https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/



13

Использование информационной схемы - это стандартный способ SQL, поэтому она должна использоваться всеми базами данных, которые ее поддерживают.


12
Это должен был быть комментарий.
underscore_d

3
Этот ответ нуждается в улучшении.
rory.ap

11
IF EXISTS 
(
    SELECT   * 
    FROM     sys.objects 
    WHERE    object_id = OBJECT_ID(N'[dbo].[Mapping_APCToFANavigator]') 
             AND 
             type in (N'U')
)
BEGIN

    -- Do whatever you need to here.

END

Здесь в приведенном выше коде имя таблицы Mapping_APCToFANavigator.


2
Если почтовый индекс, XML или данных образцов, пожалуйста , выделите эти строки в текстовом редакторе и нажмите на кнопку «код образцы» ( { }) на панели инструментов редактора , чтобы красиво формат и синтаксис выделить его!
marc_s

1
Обратите внимание, что доступ к системным таблицам может быть прекращен в будущей версии SQL Server. Вместо этого используйте представления схемы.
Оливье Жако-Дескомб

10

Если вам нужно работать с разными базами данных:

DECLARE @Catalog VARCHAR(255)
SET @Catalog = 'MyDatabase'

DECLARE @Schema VARCHAR(255)
SET @Schema = 'dbo'

DECLARE @Table VARCHAR(255)
SET @Table = 'MyTable'

IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES   
    WHERE TABLE_CATALOG = @Catalog 
      AND TABLE_SCHEMA = @Schema 
      AND TABLE_NAME = @Table))
BEGIN
   --do stuff
END

1
Ты уверен? Информационная схема на моем боксе 2005 года возвращает только текущий каталог.
Quillbreaker

8

Я знаю, что это старый вопрос, но я нашел такую ​​возможность, если вы планируете часто его называть.

create procedure Table_Exists
@tbl varchar(50)
as
return (select count(*) from sysobjects where type = 'U' and name = @tbl)
go

9
-1. Бессмысленно иметь процедуру для этого, так как это столько кода, чтобы вызывать и потреблять возврат, чем просто делать выбор. Не следует использовать sysnameтип данных varchar(50). Не следует использовать устаревшее sysobjectsпредставление и не принимает во внимание схему.
Мартин Смит

6

Вы можете использовать ниже код

IF (OBJECT_ID('TableName') IS NOT NULL )
BEGIN
  PRINT 'Table Exists'
END
ELSE
BEGIN 
  PRINT 'Table NOT Exists'
END

Или

IF (EXISTS (SELECT * FROM sys.tables WHERE [name] = 'TableName'))
BEGIN
  PRINT 'Table Exists'
END
ELSE
BEGIN 
  PRINT 'Table NOT Exists'
END

5

Просто добавив сюда, в интересах разработчиков и коллег-администраторов баз данных

скрипт, который получает @Tablename в качестве параметра

(которая может содержать или не содержать имя схемы) и возвращает информацию ниже, если существует схема:

the_name                object_id   the_schema  the_table       the_type
[Facts].[FactBackOrder] 758293761   Facts       FactBackOrder   Table

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

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

это может быть внутри процедуры и возвращать -1, например.

Например, у меня есть таблица с именем «Facts.FactBackOrder» в одной из моих баз данных хранилища данных.

Вот как я этого добился:

PRINT 'THE SERVER IS ' + @@SERVERNAME
--select db_name()
PRINT 'THE DATABASE IS ' + db_NAME() 
PRINT ''
GO

SET NOCOUNT ON
GO

--===================================================================================
-- @TableName is the parameter
-- the object we want to deal with (it might be an indexed view or a table)
-- the schema might or might not be specified
-- when not specified it is DBO
--===================================================================================

DECLARE @TableName SYSNAME

SELECT @TableName = 'Facts.FactBackOrder'
--===================================================================================
--===================================================================================
DECLARE @Schema SYSNAME
DECLARE @I INT
DECLARE @Z INT 

SELECT @TableName = LTRIM(RTRIM(@TableName))
SELECT @Z = LEN(@TableName)

IF (@Z = 0) BEGIN

            RAISERROR('Invalid @Tablename passed.',16,1)

END 

SELECT @I = CHARINDEX('.',@TableName )
--SELECT @TableName ,@I

IF @I > 0 BEGIN

        --===================================================================================
        -- a schema and table name have been passed
        -- example Facts.FactBackOrder 
        -- @Schema = Fact
        -- @TableName = FactBackOrder
        --===================================================================================

   SELECT @Schema    = SUBSTRING(@TABLENAME,1,@I-1)
   SELECT @TableName = SUBSTRING(@TABLENAME,@I+1,@Z-@I)



END
ELSE BEGIN

        --===================================================================================
        -- just a table name have been passed
        -- so the schema will be dbo
        -- example Orders
        -- @Schema = dbo
        -- @TableName = Orders
        --===================================================================================

   SELECT @Schema    = 'DBO'     


END

        --===================================================================================
        -- Check whether the @SchemaName is valid in the current database
        --===================================================================================

IF NOT EXISTS ( SELECT * FROM INFORMATION_SCHEMA.SCHEMATA K WHERE K.[SCHEMA_NAME] = @Schema ) BEGIN

            RAISERROR('Invalid Schema Name.',16,1)

END 

--SELECT @Schema  as [@Schema]
--      ,@TableName as [@TableName]


DECLARE @R1 TABLE (

   THE_NAME SYSNAME
  ,THE_SCHEMA SYSNAME
  ,THE_TABLE SYSNAME
  ,OBJECT_ID INT
  ,THE_TYPE SYSNAME
  ,PRIMARY KEY CLUSTERED (THE_SCHEMA,THE_NAME)

)

;WITH RADHE_01 AS (
SELECT QUOTENAME(SCHEMA_NAME(O.schema_id)) + '.' + QUOTENAME(O.NAME) AS [the_name]
      ,the_schema=SCHEMA_NAME(O.schema_id)
      ,the_table=O.NAME
      ,object_id =o.object_id 
      ,[the_type]= CASE WHEN O.TYPE = 'U' THEN 'Table' ELSE 'View' END 
from sys.objects O
where O.is_ms_shipped = 0
AND O.TYPE IN ('U','V')
)
INSERT INTO @R1 (
   THE_NAME 
  ,THE_SCHEMA 
  ,THE_TABLE 
  ,OBJECT_ID
  ,THE_TYPE 
)
SELECT  the_name
       ,the_schema
       ,the_table
       ,object_id
       ,the_type
FROM RADHE_01
WHERE the_schema = @Schema 
  AND the_table  = @TableName

IF (@@ROWCOUNT = 0) BEGIN 

             RAISERROR('Invalid Table Name.',16,1)

END 
ELSE BEGIN

    SELECT     THE_NAME 
              ,THE_SCHEMA 
              ,THE_TABLE 
              ,OBJECT_ID
              ,THE_TYPE 

    FROM @R1

END 

В вашем сценарии много предположений. Например, я мог легко создать таблицу с именем, dbo.[hello.world ]и скрипт не смог бы найти ее по нескольким причинам. Тем не менее, вряд ли кто-то захочет создать такую ​​таблицу, но все же. В любом случае, ваш THE_NAMEстолбец определен как sysname', yet you try to squeeze 2 столбцы sysname` и точка ( .), все они заключены в квадратные скобки ... что однажды обязательно произойдет сбой!
Дероби

@deroby Я согласен, что sysname не лучший тип данных для использования, но сценарий долгое время работал без ошибок, я бы потратил на него время только в том случае, если найду разумную ситуацию, когда он не работает. Более того, вы берете этот код, улучшаете его и публикуете здесь в качестве ответа, и я протестирую его, если он сработает, я добавлю ваш ответ.
Марчелло Миорелли

5

В SQL Server 2000 вы можете попробовать:

IF EXISTS(SELECT 1 FROM sysobjects WHERE type = 'U' and name = 'MYTABLENAME')
BEGIN
   SELECT 1 AS 'res' 
END

3
IF EXISTS 
(
    SELECT  * 

    FROM    INFORMATION_SCHEMA.TABLES 

    WHERE   TABLE_SCHEMA = 'PutSchemaHere'     
            AND  
            TABLE_NAME   = 'PutTableNameHere'
)

2

Что-то, что важно знать всем, кто еще не нашел своего решения: SQL-сервер! = MYSQL . Если вы хотите сделать это с MYSQL , это довольно просто

    $sql = "SELECT 1 FROM `db_name`.`table_name` LIMIT 1;";
    $result = mysql_query($sql);
    if( $result == false )
        echo "table DOES NOT EXIST";
    else
        echo "table exists";

Размещать это здесь, потому что это самый популярный сайт в Google.


4
-1, потому что OP точно запрашивает решение проблемы с SQL Server, а не MySQL. Он писал о MySQL, потому что знал решение для этой СУБД и хотел того же результата на SQL Server. Также ваш ответ - это даже не запрос MySQL, а код PHP, который работает с MySQL.
mordack550

1
@ mordack550, я согласен с Блаухирном. Он прав. Это самый популярный сайт в Google, чтобы узнать, существует ли таблица в SQL. У него хорошие намерения, а его информация полезна. +1
Mark

К сожалению, у Microsoft есть привычка пытаться использовать / расширять / уничтожать общие стандарты и шаблоны, такие как SQL. Мне бы очень хотелось, чтобы они дали своей реализации SQL-сервера правильное имя, чтобы люди могли однозначно идентифицировать ссылки, относящиеся к их продукту.
psaxton


2

Вы можете использовать это:

     IF OBJECT_ID (N'dbo.T', N'U') IS NOT NULL 
        BEGIN 
            print 'deleted table';
            drop table t 
        END
     else 
        begin 
            print 'table not found' 
        end

 Create table t (id int identity(1,1) not null, name varchar(30) not null, lastname varchar(25) null)
 insert into t( name, lastname) values('john','doe');
 insert into t( name, lastname) values('rose',NULL);

 Select * from t
1   john    doe
2   rose    NULL

 -- clean
 drop table t


1

- создать процедуру, чтобы проверить, существует ли таблица


DELIMITER $$

DROP PROCEDURE IF EXISTS `checkIfTableExists`;

CREATE PROCEDURE checkIfTableExists(
    IN databaseName CHAR(255),
    IN tableName CHAR(255),
    OUT boolExistsOrNot CHAR(40)
)

  BEGIN
      SELECT count(*) INTO boolExistsOrNot FROM information_schema.TABLES
      WHERE (TABLE_SCHEMA = databaseName)
      AND (TABLE_NAME = tableName);
  END $$

DELIMITER ;

- - как использовать: проверить, существует ли миграция таблиц


 CALL checkIfTableExists('muDbName', 'migrations', @output);

1
IF EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE 
TABLE_CATALOG = 'Database Name' and
TABLE_NAME = 'Table Name' and 
TABLE_SCHEMA = 'Schema Name') -- Database and Schema name in where statement can be deleted

BEGIN
--TABLE EXISTS
END

ELSE BEGIN
--TABLE DOES NOT EXISTS
END

1

Я взял здесь создание представления в качестве примера .

Потому что команды ALTER / CREATE не могут быть внутри блоков BEGIN / END. Вам нужно проверить существование и отбросить его перед созданием

IF Object_ID('TestView') IS NOT NULL
DROP VIEW TestView

GO

CREATE VIEW TestView
   as
   . . .

GO

Если вас беспокоит потеря разрешений, вы можете также написать сценарий для операторов GRANT и запустить их в конце.

Вы можете обернуть create / alter в строку и выполнить EXEC - это может быть уродливо для больших представлений

DECLARE @SQL as varchar(4000)

-- set to body of view
SET @SQL = 'SELECT X, Y, Z FROM TABLE' 

IF Object_ID('TestView') IS NULL
    SET @SQL = 'CREATE VIEW TestView AS ' + @SQL
ELSE    
    SET @SQL = 'ALTER VIEW TestView AS ' + @SQL

0

Если кто-то пытается сделать то же самое в linq to sql (или особенно linqpad), включите опцию, чтобы включить системные таблицы и представления, и сделайте этот код:

let oSchema = sys.Schemas.FirstOrDefault(s=>s.Name==a.schema )
where oSchema !=null
let o=oSchema!=null?sys.Objects.FirstOrDefault (o => o.Name==a.item && o.Schema_id==oSchema.Schema_id):null
where o!=null

учитывая, что у вас есть объект с именем в свойстве с именем item, а схема в свойстве с именем schema, где имя исходной переменной a


0

Если это будет «окончательное» обсуждение, то следует отметить, что сценарий Ларри Леонарда может также запрашивать удаленный сервер, если серверы связаны между собой.

if exists (select * from REMOTE_SERVER.MyOtherDatabase.sys.tables where name = 'MyTable')
    print 'Exists'

Возможно, более уместно добавить это в качестве комментария к ответу Леонардса или, может быть, в качестве редактирования?
EWit

0

У меня были некоторые проблемы с выбором из INFORMATIONAL_SCHEME и OBJECT_ID. Я не знаю, проблема ли это в драйвере ODBC или что-то в этом роде. Запросы из студии управления SQL оба были в порядке.

Вот решение:

SELECT COUNT(*) FROM <yourTableNameHere>

Таким образом, если запрос не выполняется, вероятно, в базе данных нет такой таблицы (или у вас нет прав доступа к ней).

Проверка выполняется путем сравнения значения (целое число в моем случае), возвращаемого исполнителем SQL, который работает с драйвером ODBC.

if (sqlexec(conectionHandle, 'SELECT COUNT(*) FROM myTable') == -1) {
  // myTable doesn't exist..
}

Сбой с каким выходом?
wscourge

@wscourge, SQL-запрос не выполнен или что-то в этом роде. Я просто проверяю возвращаемое значение из функции executor.
Майкл Квад

Добавьте это к своему ответу
wscourge

0

Есть еще один вариант, чтобы проверить, существует ли таблица в разных базах данных.

IF EXISTS(SELECT 1 FROM [change-to-your-database].SYS.TABLES WHERE NAME = 'change-to-your-table-name')
BEGIN
    -- do whatever you want
END

-1

Запустите этот запрос, чтобы проверить, существует ли таблица в базе данных:

IF(SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'YourTableName') IS NOT NULL
PRINT 'Table Exists';

-6

Учтите, в одной базе данных у вас есть таблица t1. Вы хотите запустить скрипт на другой базе данных, как - если существует t1, то больше ничего не создайте t1. Для этого откройте Visual Studio и выполните следующие действия:

Щелкните правой кнопкой мыши на t1, затем выберите Script table as, затем DROP и Create To, затем New Query Editor.

Вы найдете нужный вам запрос. Но перед выполнением этого скрипта не забудьте закомментировать оператор drop в запросе, поскольку вы не хотите создавать новый, если он уже есть.

Спасибо


В SSMS 2012 он больше не выполняет проверку «если есть», если он когда-либо делал это (я не помню, как предыдущие версии генерировали вышеуказанный скрипт). Может быть, вы ошибаетесь с тем, как другие инструменты БД выполняют скриптинг объектов таблицы?
Ивайло Славов

SSMS выполнит проверку «если есть», если вы об этом попросите. Сервис> Параметры> Обозреватель объектов SQL Server> Сценарии> «Параметры сценариев объекта»: «Проверка существования объекта» = True
Шонн Александр,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.