SQL Serverにテーブルが存在するかどうかを確認する


1143

これは、SQLステートメントを使用してSQL Server 2000/2005にテーブルが存在するかどうかを確認する方法についての最終的な議論になりたいと思います。

あなたが答えをググるとき、あなたは非常に多くの異なる答えを得ます。それを行う公式/後方および前方互換性のある方法はありますか?

これを行うには、2つの方法があります。2つのうちどちらが標準/最良の方法ですか?

最初の方法:

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;

2番目の方法:

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
sys.tablesの代わりにINFORMATION_SCHEMA.TABLESを使用し、名前でフィルタしてtype_desc値のチェックを追加するのが最適なのはなぜですか?
DanteTheSmith 2017

回答:


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では(元の投稿者への応答として)、それはSCHEMA_NAMEではなくTABLE_SCHEMAです。先端をありがとう。
Nicholas Piasecki

10
オブジェクト名のみ(つまり、スキーマなし)が一意であることが保証されていない場合、これを行うための100%フェイルセーフな方法はありません。スキーマ間で名前の競合がないDBを使用している場合は、単に "TABLE_SCHEMA = 'TheSchema'"を省略しても問題ありません。
akmad

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
Rich Rousseau

4
@akmad SQLクエリコンパイラは、クエリを実行する前にテーブルをチェックし、開始する前に失敗します。
マークK

278

また、何らかの理由で一時テーブルを確認する必要がある場合は、次のようにしてください。

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

10
この方法を使用すると、一時テーブルの接続ごとの性質が尊重されるようです。以前に投稿されたINFORMATION_SCHEMAクエリは、テーブルを作成した接続に関係なく行を返します。
リッチルソー

238

私はOBJECT_ID覚えている限りいつもスタイルを使います

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

16
これは高速であると思いますが、移植性はあまり高くありません。情報スキーマビューは、標準をサポートするすべてのDBRMSに存在することが保証されています。さらに、プレーンなOBJECT_IDはオブジェクトがテーブルであることを保証しません。
ジョー・ピネダ

9
Joeに感謝します。なぜOBJECT_ID対INFORMATION_SCHEMA.TABLES対sys.tablesを使用するのか疑問に思いました。INFORMATION_SCHEMAは標準の一部であることを指摘して、その質問にほとんど答えます。ところで面白いのは、この質問をするつもりだったデータベースエキスパートの1人があなたと同じ姓を持っていることです。データベースの良い姓である必要があります。
Apeiron 2011

24
@JoePineda:次にOBJECT_ID('TableName', 'U')、オブジェクトがテーブルであることを保証するために使用します。
Allon Guralnek、2011年

1
@AllonGuralnekでは、シンプルでポータブルな標準に従う代わりに、暗号情報を追加しますか?
定義

22
@DustinFineout:質問がタグ付けされたTSQL移植性が限り適用されませんので、。一般に、私は本当にポータブルなコードベースに出くわすことはほとんどありません。簡潔さを重視するならIF EXISTS、受け入れられた回答からそのクエリを何度も何度も書くことに勝るはずです。さらに、特にT-SQL(または実際にはその他のバリアント)のドキュメントを読むまで、すべてが暗号化されています。
Allon Guralnek、

132

以下のアプローチをご覧ください、

アプローチ1:INFORMATION_SCHEMA.TABLESビューを使用する

以下のようなクエリを記述して、Customersテーブルが現在のデータベースに存在するかどうかを確認できます。

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

アプローチ2:OBJECT_ID()関数を使用する

以下のようなOBJECT_ID()関数を使用して、Customersテーブルが現在のデータベースに存在するかどうかを確認できます。

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システムテーブルを直接使用することは避けてください。SQLServerの将来の一部のバージョンでは、システムテーブルへの直接アクセスが廃止される予定です。Microsoft BOLリンクに従って、Microsoftはsys.sysobjectsシステムテーブルではなくカタログビューsys.objects / sys.tablesを直接使用することを提案しています。

  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/


37

別のデータベースでテーブルを探す:

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

26

OBJECT_IDメソッドを使用する方がおそらく少し簡単になる1つの状況について言及したかっただけです。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 existsdropステートメントにキーワードを追加することで、ドロップする前に存在しないオブジェクトをチェックする機能を簡素化しました。例えば、

drop table if exists mytablename

OBJECT_ID/ INFORMATION_SCHEMAラッパーと同じことを1行のコードで行います。

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




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の将来のバージョンで廃止される可能性があることに注意してください。代わりにスキーマビューを使用してください。
Olivier Jacot-Descombes 14

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ボックスの情報スキーマは、現在のカタログのみを返します。
キルブレーカー、2013

8

私はそれが古い質問であることを知っていますが、あなたが頻繁にそれを呼ぶことを計画しているなら、私はこの可能性を見つけました。

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

9
-1。単に選択を行うのと同じくらい多くのコードを呼び出して戻りを消費するのと同じように、このためのプロシージャを持つことは無意味です。sysnameデータ型notを使用する必要があります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

ここに追加するだけで、開発者と他のDBAの利益のために

@Tablenameをパラメーターとして受け取るスクリプト

(schemanameが含まれる場合と含まれない場合があります)、schema.tableが存在する場合は以下の情報を返します。

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

テーブルまたはビューが存在するかどうかをテストする必要があるたびに他のスクリプト内で使用されるこのスクリプトを作成し、存在する場合は、そのobject_idを他の目的で使用するために取得します。

空の文字列、間違ったスキーマ名、または間違ったテーブル名を渡した場合、エラーが発生します。

これはプロシージャの内部にあり、たとえば-1を返します。

例として、データウェアハウスデータベースの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 16

@deroby私はsysnameが使用するのに最適なデータ型ではないことに同意しますが、スクリプトは何のエラーもなく長時間実行されていますが、機能しない合理的な状況が見つかった場合にのみ時間を費やします。さらに良いことに、あなたはこのコードを受け取り、それを改善し、ここに回答として投稿します。私はそれをテストします。それが機能する場合、私はあなたの回答に賛成票を投じます。
Marcello Miorelli、2016

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サーバー!= MYSQLMYSQLで実行したい場合、それは非常に簡単です

    $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がMySQLサーバーではなく、問題に対するSQL Serverソリューションを正確に要求しているためです。彼はそのDBMSのソリューションを知っていて、SQL Serverでも同じ結果を望んだため、MySQLについて書きました。また、あなたの答えはMySQLクエリではなく、MySQLで動作するPHPコードです。
mordack550 2014

1
@ mordack550、私はBlauhirnに同意します。彼は正しいです。これは、SQLにテーブルが存在するかどうかを確認するためのGoogleのトップヒットです。彼の意図はよく、彼の情報は役に立ちます。+1
マーク

MicrosoftがSQLのような一般的な標準やパターンを採用/拡張/消滅しようとする習慣があるのは残念です。SQLサーバーの実装に適切な名前を付けて、製品固有の参照を明確に識別できるようにしてほしいと思います。
psaxton 2016年


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というプロパティに名前を持つオブジェクトがあり、スキーマと呼ばれるプロパティにスキーマがあり、ソース変数名が a


0

これが「究極の」ディスカッションになる場合、サーバーがリンクされていれば、ラリーレナードのスクリプトがリモートサーバーにもクエリを実行できることに注意してください。

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

おそらく、これをLeonards回答へのコメントとして、または編集として追加する方が適していますか?
EWit 2014

0

INFORMATIONAL_SCHEMEとOBJECT_IDのどちらかを選択する際に問題が発生しました。ODBCドライバーの問題かどうかはわかりません。SQL管理スタジオからのクエリはどちらも問題ありませんでした。

これが解決策です:

SELECT COUNT(*) FROM <yourTableNameHere>

したがって、クエリが失敗した場合、おそらくデータベースにそのようなテーブルはありません(または、そのテーブルへのアクセス権限がありません)。

チェックは、ODBCドライバーを処理するSQLエグゼキューターによって返された値(私の場合は整数)を比較することによって行われます。

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

どの出力で失敗しますか?
wscourge

@ wscourge、SQLクエリが失敗したなど。executor関数からの戻り値を確認するだけです。
Michael Quad

回答に追加してください
wscourge

0

テーブルがデータベース全体に存在するかどうかを確認するもう1つのオプションがあります。

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

1つのデータベースにテーブルt1があるとします。他のデータベースでスクリプトを実行したい場合-t1が存在する場合、他に何もせずにt1を作成します。これを行うには、ビジュアルスタジオを開き、次の操作を行います。

t1を右クリックし、[スクリプトテーブル]、[ドロップして作成]、[新しいクエリエディター]の順にクリックします。

目的のクエリが見つかります。ただし、そのスクリプトを実行する前に、クエリ内のdropステートメントをコメントアウトすることを忘れないでください。既に存在する場合は、新しいステートメントを作成したくないからです。

ありがとう


SSMS 2012では、if-existsチェックを実行しませんでした(以前のバージョンで上記のスクリプトがどのように生成されたかは覚えていません)。たぶん、他のdbツールがテーブルオブジェクトをスクリプト化している方法に誤りがあるのでしょうか。
Ivaylo Slavov 2015

SSMSは、必要に応じて存在チェックを実行します。[ツール]> [オプション]> [SQL Serverオブジェクトエクスプローラ]> [スクリプト]> [オブジェクトスクリプトオプション]:[オブジェクトの存在を確認] = True
Seann Alexander
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.