关于tsql:检查SQL Server中是否存在表

Check if table exists in SQL Server

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

当你用谷歌搜索答案时,你会得到很多不同的答案。有没有一种正式的/前后兼容的方式?

有两种可能的方法。这两种方法中的哪一种是标准的/最好的?

第一种方式:

1
2
3
4
5
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;

第二种方式:

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

mysql提供了

1
SHOW TABLES LIKE '%tablename%';

语句。我在找类似的东西。


对于这样的查询,最好使用INFORMATION_SCHEMA视图。这些视图(大部分)是跨许多不同数据库的标准视图,很少在版本之间进行更改。

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

1
2
3
4
5
6
7
IF (EXISTS (SELECT *
                 FROM INFORMATION_SCHEMA.TABLES
                 WHERE TABLE_SCHEMA = 'TheSchema'
                 AND  TABLE_NAME = 'TheTable'))
BEGIN
    --Do Stuff
END


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

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


我记得我们一直使用OBJECT_ID样式

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


请看下面的方法,

方法1:使用information_schema.tables视图

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

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

方法2:使用object_id()函数

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

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

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

我们可以使用sys.objects目录视图检查表的存在,如下所示:

1
2
3
4
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目录视图检查表的存在,如下所示:

1
2
3
4
 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系统表。

1
2
3
4
  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/


在其他数据库中查找表:

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

只是想提到一种情况,在这种情况下,使用OBJECT_ID方法可能会更容易一些。INFORMATION_SCHEMA视图是每个数据库下的对象。-

The information schema views are defined in a special schema named
INFORMATION_SCHEMA. This schema is contained in each database.

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

因此,使用

1
2
3
4
5
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将允许您在框外执行此操作。前-

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

同样有效

1
2
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年开始,微软通过在drop语句中添加if exists关键字,简化了在删除之前检查不存在对象的功能。例如,

1
drop table if exists mytablename

将在1行代码中执行与OBJECT_ID/INFORMATION_SCHEMA包装器相同的操作。

DROP IF EXISTS – new thing in SQL Server 2016


1
IF OBJECT_ID('mytablename') IS NOT NULL

使用信息模式是SQL的标准方法,因此所有支持它的数据库都应该使用它。


如果需要处理不同的数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
2
3
4
5
6
7
8
9
10
11
12
13
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


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

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


为了开发人员和DBA同事的利益,只需在这里添加

接收@tablename作为参数的脚本

(可能包含架构名称,也可能不包含架构名称),如果存在schema.table,则返回以下信息:

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

每次我需要测试一个表或视图是否存在时,我都会生成这个脚本,在其他脚本中使用它,当它存在时,我会让它的对象ID用于其他目的。

当您传递空字符串、错误的架构名或错误的表名时,它会引发错误。

这可能在一个过程中,例如返回-1。

例如,我的一个数据仓库数据库中有一个名为"facts.factbackorder"的表。

我就是这样做到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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


在SQL Server 2000中,您可以尝试:

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

1
2
3
4
5
6
7
8
9
10
IF EXISTS
(
    SELECT  *

    FROM    INFORMATION_SCHEMA.TABLES

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    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

对于那些还没有找到解决方案的人来说,需要知道一些重要的事情:SQL Server!= MySQL。如果你想用MySQL来做,这很简单

1
2
3
4
5
6
    $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";

把这个贴在这里,因为它是谷歌的热门。


1
select name from SysObjects where xType='U' and name like '%xxx%' order by name

1
2
3
4
5
IF EXISTS (   SELECT * FROM   dbo.sysobjects WHERE  id = OBJECT_ID(N'dbo.TableName') AND OBJECTPROPERTY(id, N'IsUserTable') = 1 )
BEGIN
  SELECT * FROM dbo.TableName;
END
GO

我在选择信息方案和对象ID时遇到了一些问题。我不知道这是ODBC驱动程序的问题还是其他问题。来自SQL Management Studio的查询都正常。

解决方案如下:

1
SELECT COUNT(*) FROM <yourTableNameHere>

因此,如果查询失败,那么数据库中可能没有这样的表(或者您没有访问它的权限)。

检查是通过比较处理ODBC驱动程序的SQL执行器返回的值(在我的例子中是整数)来完成的。

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


如果这是"终极"讨论,那么应该注意的是,Larry Leonard的脚本也可以查询远程服务器(如果服务器链接)。

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


----创建检查表是否存在的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 ;

----如何使用:检查表迁移是否存在

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

如果有人试图在Linq to SQL(或尤其是LinqPad)中执行相同的操作,请启用包含系统表和视图的选项,并执行以下代码:

1
2
3
4
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的源变量名。


考虑在一个数据库中有一个表T1。您希望在其他数据库上运行脚本,例如-如果存在T1,则不执行任何其他操作创建T1。要执行此操作,请打开Visual Studio并执行以下操作:

右键单击T1,然后编写表脚本为,然后删除并创建到,然后新建查询编辑器。

您将找到所需的查询。但在执行该脚本之前,不要忘记注释掉查询中的drop语句,因为如果已经有了该语句,就不希望创建新语句。

谢谢