【问题标题】:Check if table exists and if it doesn't exist, create it in SQL Server 2008检查表是否存在,如果不存在,请在 SQL Server 2008 中创建
【发布时间】:2011-08-22 13:27:18
【问题描述】:

我正在 SQL Server 2008 中编写存储过程。 我需要检查数据库中是否存在表。如果没有,那么我需要创建它。

我该怎么做?

【问题讨论】:

  • 相关,如果不重复:Check if table exists in SQL Server.
  • 这是一个很好的问题,每个使用 SQL Server 的人最终都会问。遗憾的是 SQL Server 没有友好的 Oracle 样式 CREATE OR REPLACE
  • 对于 MySQL,您可以使用 CREATE TABLE IF NOT EXISTS ...

标签: sql sql-server tsql sql-server-2008-r2


【解决方案1】:
Declare @Username varchar(20)
Set @Username = 'Mike'

if not exists 
(Select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'tblEmp')

Begin
    Create table tblEmp (ID int primary key, Name varchar(50))
    Print (@Username + ' Table created successfully')
End

Else

Begin
    Print (@Username + ' : this Table Already exists in the database')
End

【讨论】:

  • 欢迎来到 StackOverflow。在回答问题时,也可以考虑添加解释。大多数情况下,仅靠代码并不是很有帮助。
【解决方案2】:

让我们通过以下脚本创建一个带有表的示例数据库:

CREATE DATABASE Test
GO
USE Test
GO
CREATE TABLE dbo.tblTest (Id INT, Name NVARCHAR(50))

方法 1:使用 INFORMATION_SCHEMA.TABLES 视图

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

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

上述查询检查当前数据库中所有模式的 tblTest 表是否存在。如果您想检查指定 Schema 和指定数据库中的表是否存在,那么我们可以编写上述查询,如下所示:

IF EXISTS (SELECT * FROM Test.INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = N'dbo'  AND TABLE_NAME = N'tblTest')
BEGIN
  PRINT 'Table Exists'
END

这种方法的优点:INFORMATION_SCHEMA 视图可以跨不同的 RDBMS 系统移植,因此移植到不同的 RDBMS 不需要任何更改。

方法二:使用 OBJECT_ID() 函数

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

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

为表名称指定数据库名称和架构名称部分是可选的。但是指定数据库名称和模式名称提供了一个选项来检查指定数据库和指定模式中的表是否存在,而不是在所有模式中检查当前数据库。下面的查询表明,即使当前数据库是 MASTER 数据库,我们也可以在Test 数据库中检查dbo 架构中的tblTest 表是否存在。

USE MASTER
GO
IF OBJECT_ID(N'Test.dbo.tblTest', N'U') IS NOT NULL
BEGIN
  PRINT 'Table Exists'
END

优点:容易记住。关于OBJECT_ID() 函数的另一个值得注意的点是:它提供了一个选项来检查在当前连接上下文中创建的临时表是否存在。所有其他方法检查是否存在跨所有连接上下文创建的临时表,而不仅仅是当前连接上下文。下面的查询显示了如何使用OBJECT_ID() 函数检查临时表是否存在:

CREATE TABLE #TempTable(ID INT)
GO
IF OBJECT_ID(N'TempDB.dbo.#TempTable', N'U') IS NOT NULL
BEGIN
  PRINT 'Table Exists'
END
GO

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

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

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

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

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

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

Sys.Tables 目录视图从Sys.Objects 目录视图继承行,Sys.objects 目录视图称为基础视图,而sys.Tables 称为派生视图。 Sys.Tables 将只返回 Table 对象的行,而 Sys.Object view 除了返回 table 对象的行外,它还返回对象的行,例如:存储过程、视图等。

方法五:避免使用 sys.sysobjects 系统表

我们应该避免直接使用sys.sysobjects 系统表,在未来的某些Sql Server 版本中将不推荐直接访问它。根据 [Microsoft BOL][1] 链接,Microsoft 建议直接使用目录视图 sys.objects/sys.tables 而不是 sys.sysobjects 系统表。

IF EXISTS(SELECT name FROM sys.sysobjects WHERE Name = N'tblTest' 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/

【讨论】:

  • 重要的是要注意这个答案提供了哪种方法需要指定数据库,哪些不需要。这是非常有价值的,对于在同一实例上运行多个相同数据库时运行以设置和更新操作数据库的脚本,这是关键!很好的信息。
【解决方案3】:
IF (EXISTS (SELECT * 
                 FROM INFORMATION_SCHEMA.TABLES 
                 WHERE  TABLE_NAME = 'd020915'))
BEGIN
  declare @result int
  set @result=1
  select @result as result
END

【讨论】:

    【解决方案4】:

    已编辑

    您可以查看 sys.tables 以检查是否存在所需的表:

    IF  NOT EXISTS (SELECT * FROM sys.tables
    WHERE name = N'YourTable' AND type = 'U')
    
    BEGIN
    CREATE TABLE [SchemaName].[YourTable](
        ....
        ....
        ....
    ) 
    
    END
    

    【讨论】:

      【解决方案5】:

      为了对比,我喜欢使用如下所示的 object_id 函数。它更容易阅读,您不必担心 sys.objects 与 sysobjects 与 sys.all_objects 与 sys.tables 相比。基本形式:

      IF object_id('MyTable') is not null
          PRINT 'Present!'
      ELSE
          PRINT 'Not accounted for'
      

      当然,如果存在具有该名称的 any 对象,这将显示为“Present”。如果您只想检查表格,则需要:

      IF object_id('MyTable', 'U') is not null
          PRINT 'Present!'
      ELSE
          PRINT 'Not accounted for'
      

      它也适用于临时表:

      IF object_id('tempdb.dbo.#MyTable') is not null
          PRINT 'Present!'
      ELSE
          PRINT 'Not accounted for'
      

      【讨论】:

      • 我通常会看到使用的另一种方法(检查 sys 表),但这似乎清晰且紧凑。有什么理由不喜欢这种方法而不是接受的答案? (比如SQL迁移到不同数据库提供者的兼容性问题、速度等)?
      【解决方案6】:

      尝试以下语句来检查数据库中是否存在表:

      If not exists (select name from sysobjects where name = 'tablename')
      

      您可以在 if 块中创建表格。

      【讨论】:

      • 虽然该语法可以工作,但sysobjects 是一个兼容性视图,它的存在只是为了避免破坏旧代码。我的建议是对只针对 SQL Server 2008 实例的代码使用系统目录视图(例如sys.objects、sys.tables),对需要可移植的代码使用信息架构视图(例如information_schema.tables)。您可以在此处找到有关不同视图的更多信息:Querying the SQL Server System Catalog
      【解决方案7】:

      如果我没记错的话,这应该可行:

          if not exists (Select 1 from tableName)
      create table ...
      

      【讨论】:

      • 如果表存在但为空怎么办,这种情况下会这样
      • @SQLMeance 哦,好的,我从您的回答中了解到您正在检查 sys.objects 中的“U”类型,您能帮我理解一下,为什么推荐这个?表可以存在于其他任何地方吗?提前谢谢你
      【解决方案8】:

      类似的东西

      IF  NOT EXISTS (SELECT * FROM sys.objects 
      WHERE object_id = OBJECT_ID(N'[dbo].[YourTable]') AND type in (N'U'))
      
      BEGIN
      CREATE TABLE [dbo].[YourTable](
          ....
          ....
          ....
      ) 
      
      END
      

      【讨论】:

      • 尊重地考虑一些更改(为了执行计划)使用索引字段而不是 *(object_id 是此表中通常引用的数字字段)使用type = 'U' 而不是 type in (N'U')(列 _type 是 char 类型,使用 Nchar 会导致隐式转换这通常会导致基数估计器出现问题)if (not exists (select object_id from sys.objects where object_id = OBJECT_ID(N'[dbo].[client_tgi_g67_period_list]') and type = 'U'))
      • IF 和 NOT 之间的第二个空格是故意的吗?
      猜你喜欢
      • 2020-04-07
      • 1970-01-01
      • 2016-03-06
      • 2015-10-05
      • 2010-09-15
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多