检查SQL Server中是否存在表

Vin*_*ent 1068 t-sql sql-server sql-server-2005 sql-server-2000

我希望这是关于如何使用SQL语句检查SQL Server 2000/2005中是否存在表的最终讨论.

当谷歌找到答案时,你会得到很多不同的答案.这样做是否有正式/后向和前向兼容的方式?

这有两种可行的方法.这两者中哪一个是标准/最佳方式?

第一种方式:

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;
Run Code Online (Sandbox Code Playgroud)

第二种方式:

IF OBJECT_ID (N'mytablename', N'U') IS NOT NULL 
   SELECT 1 AS res ELSE SELECT 0 AS res;
Run Code Online (Sandbox Code Playgroud)

MySQL提供简单

SHOW TABLES LIKE '%tablename%'; 
Run Code Online (Sandbox Code Playgroud)

声明.我正在寻找类似的东西.

akm*_*mad 1263

对于像这样的查询,最好使用INFORMATION_SCHEMA视图.这些视图(大多数)是许多不同数据库的标准视图,很少从版本更改为版本.

要检查表是否存在,请使用:

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

  • 要检查临时表,我们必须查询tempdb数据库并使用LIKE运算符作为表名`SELECT*FROM tempdb.INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA ='TheSchema'AND TABLE_NAME LIKE'#TheTable%'` (22认同)
  • 效果很好!但是在T-SQL中(响应原始海报),它是TABLE_SCHEMA,而不是SCHEMA_NAME.谢谢你的提示. (12认同)
  • 鉴于单独的对象名称(即没有架构)不能保证是唯一的,没有100%的故障保护方法来执行此操作.如果您正在使用跨模式没有命名冲突的数据库,那么只需省略"TABLE_SCHEMA ='TheSchema'"就可以了. (10认同)
  • 下面使用OBJECT_ID函数的响应确实可以正确运行每个连接临时表 - http://stackoverflow.com/a/2155299/16147 (4认同)
  • @akmad SQL查询编译器将在运行查询之前检查表,并在启动之前失败. (4认同)
  • 上面的tempdb INFORMATION_SCHEMA查询将返回在任何连接上创建的临时表的行,而不仅仅是当前连接.这可能导致"if exists,then drop"语句失败. (3认同)
  • 如何避免在 where 子句中出现 schema_name?使用 object_id() 方法的好处是它默认为当前模式。 (2认同)
  • 这个答案并不关心它是视图还是表。如果您需要知道它是否真的是一个表,您还需要检查 TABLE_TYPE 列。 (2认同)

Jam*_*mer 263

另请注意,如果出于任何原因需要检查临时表,您可以执行以下操作:

if OBJECT_ID('tempdb..#test') is not null
 --- temp table exists
Run Code Online (Sandbox Code Playgroud)

  • 使用此方法似乎尊重临时表的每个连接性质.无论创建表的连接如何,早期发布的INFORMATION_SCHEMA查询都将返回行. (10认同)

Bob*_*ing 229

OBJECT_ID只要我记得,我们总是使用这种风格

IF OBJECT_ID('*objectName*', 'U') IS NOT NULL 
Run Code Online (Sandbox Code Playgroud)

  • @JoePineda:然后你使用`OBJECT_ID('TableName','U')`来保证对象是一个表. (23认同)
  • @DustinFineout:问题被标记为[tag:tsql],因此可移植性不适用.一般来说,我遇到了很少的真正可移植的代码库,如果简洁得到了重视,那么肯定会一遍又一遍地从接受的答案中写出"IF EXISTS"查询.此外,在您阅读文档之前,一切都是神秘的,尤其是在T-SQL(或其他任何变体)中. (22认同)
  • 我相信这会很快,但不是很便携.保证信息模式视图存在于支持该标准的任何DBRMS上.此外,plain OBJECT_ID不保证对象是表. (16认同)
  • 谢谢Joe,我想知道你为什么要使用OBJECT_ID和INFORMATION_SCHEMA.TABLES vs sys.tables.指出INFORMATION_SCHEMA是标准的一部分,几乎可以回答这个问题.顺便说一句,有趣的是,我的数据库专家之一,我要问这个问题和你的姓氏一样,必须是数据库的良好姓氏. (9认同)

Bra*_*der 121

请参阅以下方法,

方法1:使用INFORMATION_SCHEMA.TABLES视图

我们可以编写如下的查询来检查当前数据库中是否存在Customers表.

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

方法2:使用OBJECT_ID()函数

我们可以使用如下的OBJECT_ID()函数来检查当前数据库中是否存在Customers表.

IF OBJECT_ID(N'dbo.Customers', N'U') IS NOT NULL
BEGIN
    PRINT 'Table Exists'
END
Run Code Online (Sandbox Code Playgroud)

方法3:使用sys.Objects目录视图

我们可以使用Sys.Objects目录视图来检查Table的存在,如下所示:

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

方法4:使用sys.Tables目录视图

我们可以使用Sys.Tables目录视图来检查Table的存在,如下所示:

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

方法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
Run Code Online (Sandbox Code Playgroud)

参考:http://sqlhints.com/2014/04/13/how-to-check-if-a-table-exists-in-sql-server/

  • 如果需要考虑表模式(例如“dbo”或类似的),请记住适应上面的大部分内容。如果在不同的模式中创建相同的表名,这可能会避免以后出现问题。 (2认同)

小智 37

在不同的数据库上查找表:

if exists (select * from MyOtherDatabase.sys.tables where name = 'MyTable')
    print 'Exists'
Run Code Online (Sandbox Code Playgroud)


ili*_*ode 24

只想提一种情况,使用该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;
Run Code Online (Sandbox Code Playgroud)

只会反映出的内容[database].如果您想检查另一个数据库中的表是否存在,而不是[database]每次都动态更改,OBJECT_ID则可以直接执行此操作.EX-

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

同样有效

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

SQL SERVER 2016编辑:

从2016年开始,Microsoft通过在语句中添加if exists关键字,简化了在删除之前检查不存在的对象的能力drop.例如,

drop table if exists mytablename
Run Code Online (Sandbox Code Playgroud)

将在一行代码中执行与OBJECT_ID/ INFORMATION_SCHEMAwrappers 相同的操作.

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


san*_*alk 22

IF OBJECT_ID('mytablename') IS NOT NULL 
Run Code Online (Sandbox Code Playgroud)


Vin*_*vic 14

使用信息模式是SQL标准的方法,所以它应该被支持它的所有数据库使用.

  • 这应该是一个评论. (11认同)
  • 这个答案需要改进. (3认同)

小智 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
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,表名是Mapping_APCToFANavigator.

  • 如果您发布代码,XML或数据样本,请**在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的"代码示例"按钮(`{}`),以便很好地格式化和语法突出显示它! (2认同)

Eve*_*ien 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
Run Code Online (Sandbox Code Playgroud)

  • 你确定吗?我的 2005 框中的信息架构仅返回当前目录。 (3认同)

Rez*_*abi 9

您可以使用以下代码

IF (OBJECT_ID('TableName') IS NOT NULL )
BEGIN
  PRINT 'Table Exists'
END
ELSE
BEGIN 
  PRINT 'Table NOT Exists'
END
Run Code Online (Sandbox Code Playgroud)

或者

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


dko*_*dko 8

我知道这是一个老问题,但如果你打算经常打电话,我发现了这种可能性.

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

  • -1.无意义的有一个程序,因为只需要执行select就可以调用和使用返回的代码.应该使用`sysname`数据类型而不是`varchar(50)`.不应该使用已弃用的`sysobjects`视图并且不考虑模式. (9认同)

Mar*_*lli 5

只需添加此处,以便开发人员和其他DBA的利益

接收@Tablename作为参数的脚本

(如果schema.table存在,则可能包含或不包含schemaname)并返回以下信息:

the_name                object_id   the_schema  the_table       the_type
[Facts].[FactBackOrder] 758293761   Facts       FactBackOrder   Table
Run Code Online (Sandbox Code Playgroud)

每当我需要测试表或视图是否存在时,我就生成了在其他脚本中使用的脚本,当它出现时,将其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 
Run Code Online (Sandbox Code Playgroud)


dip*_*vil 5

SQL Server 2000 中,您可以尝试:

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