一時テーブルが存在するかどうかを確認し、存在する場合は一時テーブルを作成する前に削除します。


663

次のコードを使用して、一時テーブルが存在するかどうかを確認し、存在する場合はテーブルを削除してから再作成します。列を変更しない限り、問題なく動作します。後で列を追加すると、「列が無効です」というエラーが表示されます。私が間違っていることを教えてください。

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
)

select company, stepid, fieldid from #Results

--Works fine to this point

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
    NewColumn            NVARCHAR(50)
)

select company, stepid, fieldid, NewColumn from #Results

--Does not work

列はどこに追加しますか?エラーを引き起こしている正確なコードを投稿できますか?
マクロ

#Resultsテーブルに列を追加しています。上記のコードをコピーして初めて実行すると、エラーは発生しません。一時テーブルに列を追加し、selectステートメントに列を追加すると、列が見つからない(またはそのようなもの)と表示されます。
Sridhar、

22
次のパターンの使用を検討してください:BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT。トランザクションが成功した場合、テーブルは削除されます。失敗すると、テーブルも削除されます(トランザクション内で作成されたため)。いずれの場合でも、テーブルがすでに存在するかどうかを確認する必要はありません。
ハインツィ

1
GOステートメントだけが必要なようです。
sam yi

回答:


734

エラーを再現できません。

多分私は問題を理解していません。

SQL Server 2005では、2番目の選択結果に余分な「foo」列が表示され、次のようにうまく機能します。

IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
GO
CREATE TABLE #Results ( Company CHAR(3), StepId TINYINT, FieldId TINYINT )
GO
select company, stepid, fieldid from #Results
GO
ALTER TABLE #Results ADD foo VARCHAR(50) NULL
GO
select company, stepid, fieldid, foo from #Results
GO
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
GO

1
OBJECT_ID( 'tempdb ..#Results')IS NOT NULL DROP TABLE#Results` CREATE TABLE #Results(Company CHAR(3)、StepId INT)select company、selectid from #results now go back back to the create statement and add a end.change selectステートメントのcolumn fieldidで、fieldidを含めて実行します。
Sridhar

28
'tempdb..#name'まさに私が必要としたものです。'dbo.#name'ばかみたいにを使っていました。tempdbパーツを入手しましたが、ダブルドットはどうですか?
Conrad.Dean

77
@ Conrad.Deanダブルドットは.dboの略です。
deutschZuid

32
@deutschZuidダブルドットがユーザーのデフォルトスキーマであると言う方がより正確です。通常、これはdboです(これは素晴らしいアイデアではありません
。dbo

8
コードがOPと非常に異なるため、「再現できません」ステートメントは意味がありません。あなたがそれを別の方法で機能させることができてうれしいです。
Gerard ONeill、2015年

85

ステートメントは正しい順序である必要があります

  1. テーブルの変更文
  2. GO
  3. ステートメントを選択します。

間に「GO」がないと、全体が1つのスクリプトと見なされ、selectステートメントが列を検索するときに、そのスクリプトは見つかりません。

'GO'を使用すると、スクリプトの 'GO'までの部分が1つのバッチと見なされ、 'GO'の後にクエリに入る前に実行されます。


7
これは正解としてマークする必要があります。SELECTが実際に作成テーブルの前に実行されるわけではありません。#Idと呼ばれる既存のテーブルがまだ存在しないため、実行前に解析されてエラーがスローされます。 selectステートメントが解析される時間。そこにGOを追加すると、クエリがバッチに分割され、バッチごとに解析および実行されます。
ダボス

2
これとトップアンサーの間の投票の違いは信じられません。コードを大幅に変更しました-理由を説明せずに-それは応答として無意味でした。
underscore_d

63

dropping一時テーブルの代わりに、再作成してtruncate再利用できます

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    Truncate TABLE #Results
else
    CREATE TABLE #Results
    (
        Company             CHAR(3),
        StepId              TINYINT,
        FieldId             TINYINT,
    )

あなたが使用している場合Sql Server 2016Azure Sql Database、その後一時テーブルを削除して再作成するための構文の下に使用します。詳細はこちらMSDN

構文

DROP TABLE [存在する場合] [database_name。[schema_name]。| schema_name。] table_name [、... n]

クエリ:

DROP TABLE IF EXISTS tempdb.dbo.#Results
CREATE TABLE #Results
  (
   Company             CHAR(3),
   StepId              TINYINT,
   FieldId             TINYINT,
  )

そうですtruncate/reuse方法がより効率的であるDROP TABLE IF EXISTSSql Server 2016Azure Sql Database同様に。これはそうではありませんか?
JDawg 2017年

@prdpなぜDROP TABLE IF ExistsSQL 2016またはAzure を提案するのですか?構文はSQL 2008以降で使用できます。回答のMSDNリンクを参照してください。パフォーマンスファクター?
HappyTown 2017

4
気にしないで。私が今実現し、DROP TABLESQL Server 2008のからサポートされていますが、IF EXISTS句は、2016年に導入されました
HappyTown

1
私が使用しますINTOdbo.HistoricoUserからのINTO #HistoricoUserTableを選択します
Kiquenet

54

問題は、実行をバッチに分割するために、間にGOステートメントを追加する必要があることだと思います。2番目のドロップスクリプトとして、つまりIF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results単一バッチの一部である一時テーブルをドロップしませんでした。以下のスクリプトをお試しください。

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
)

GO

select company, stepid, fieldid from #Results

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
    NewColumn            NVARCHAR(50)
)

GO

select company, stepid, fieldid, NewColumn from #Results

1
注意してください。tempdb..上記のコードでは非常に重要です。一時テーブル名の前に置く必要があります。単にチェックするだけOBJECT_ID('#Results')では不十分です。一時テーブルはTempDBデータベースに格納されます。マイクロソフトパー:TempDBのシステムデータベースは、SQL Serverのインスタンスに接続するか、SQLデータベースに接続しているすべてのユーザーが利用できるグローバルリソースです
ICODE

ありがとう、@ iCode。これが一時テーブルを削除するための鍵です。それを実行する tempdb必要があります。そうしないと消えません。
Alex

37

これは、1行のコードで実現できます。

IF OBJECT_ID('tempdb..#tempTableName') IS NOT NULL DROP TABLE #tempTableName;   

1
私はこれを毎日見なければなりません
Ab Bennett

28

これは私のために働きました: social.msdn.microsoft.com/Forums/en/transactsql/thread/02c6da90-954d-487d-a823-e24b891ec1b0?prof=required

if exists (
    select  * from tempdb.dbo.sysobjects o
    where o.xtype in ('U') 

   and o.id = object_id(N'tempdb..#tempTable')
)
DROP TABLE #tempTable;

1
これは、条件付きテーブルドロップの構文が異なるだけです。それは興味深いですが、OPの質問を解決しません。そのほとんどは冗長です。OBJECT_ID(N'tempdb ..#Results ')がnullでないことを確認するだけで、オブジェクトがすでに存在することを証明するには十分です。
ダボス

21

OBJECT_ID私にとってはうまくいかないので、私の側からのちょっとしたコメント。それは常にそれを返します

`#tempTableは存在しません

..それ存在してますが。私はそれが次の_ように異なる名前で保存されていることを発見しました(下線で後置):

#tempTable________

これは私にとってうまくいきます:

IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#tempTable%') BEGIN
   DROP TABLE #tempTable;
END;

6
注意:このコードは、任意のスレッドによって作成されたテーブルを検出します。単一の一時テーブルは、ストアドプロシージャのスレッド/呼び出し元ごとに個別に作成されます。そのため、名前にアンダースコアが付けられ、スレッド/プロセスごとに異なるコピーが存在します。Object_IDは、SQL 2005以降を使用している限り、現在のスレッドで問題なく機能します。
Bytemaster

12

SQL Serverの新しいバージョン(2016以降)のいずれかを使用している場合は、以下の構文を使用できます。

DROP TABLE IF EXISTS schema.yourtable(even temporary tables #...)

1
私はSSMS 17.3を使用していますし、これができますIncorrect syntax near the keyword 'IF'.
StingyJack

7
@StingyJack SQL構文はSSMSのバージョン関連ではなく、SQL Serverのバージョン関連なので。このIF [NOT] EXISTS句はSQL Server 2016から利用できます。使用しているSSMSのバージョンは関係ありません。
2018年

10

pmac72は、GOを使用してクエリをバッチに分割し、ALTERを使用しています。

同じバッチを実行しているようですが、変更後に2回実行しています:DROP ... CREATE ... edit ... DROP ... CREATE ..

おそらく、正確なコードを投稿して、何が起こっているのかを確認してください。


7

通常、一時テーブルを既に作成しているときにこのエラーが発生しました。SQLステートメントでエラーをチェックするコードは、「古い」一時テーブルが配置されていることを確認し、一時テーブルが削除されなかったかのように、後のステートメントで列数のカウントを誤って返します。

列の数が少ないバージョンを既に作成した後で一時テーブルの列数を変更した後、テーブルをドロップしてクエリを実行します。


6

私は最近、DBAが次のようなことをするのを見ました。

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)

2
このtryステートメントは、テーブルを削除しようとしたときに発生する可能性のある他のエラーをキャッチします。このコードは、試行が失敗する唯一の理由が、テーブルが存在しないためであると想定しています。ほとんどの場合それはおそらく機能するでしょうが、私はそれを保証しません。その他の理由でtryステートメントが失敗した場合は、テーブルの作成時にエラーが発生します。これは、テーブルの削除に関する実際の問題を覆い隠してしまうためです。
ダボス

これは機能しますが、スマートで完璧なソリューションがある場合、私は難しい方法を推奨しません。また、OPは2005バージョンを指定しましたが、try catchブロックは古いバージョンではサポートされていません
dejjub-AIS

これに関するもう1つの問題は、try / catch対ロジックを使用するイデオロギーです。:あなたは、ここでの議論のより見ることができますstackoverflow.com/questions/17335217/try-catch-or-if-statement/...
logixologist

3

私のコードでは、Source変更するDestinationテーブルと、それらの変更に一致する必要があるテーブルを使用しています。

-- 
-- Sample SQL to update only rows in a "Destination" Table
--  based on only rows that have changed in a "Source" table
--


--
-- Drop and Create a Temp Table to use as the "Source" Table
--
IF OBJECT_ID('tempdb..#tSource') IS NOT NULL drop table #tSource
create table #tSource (Col1 int, Col2 int, Col3 int, Col4 int)

--
-- Insert some values into the source
--
Insert #tSource (Col1, Col2, Col3, Col4) Values(1,1,1,1)
Insert #tSource (Col1, Col2, Col3, Col4) Values(2,1,1,2)
Insert #tSource (Col1, Col2, Col3, Col4) Values(3,1,1,3)
Insert #tSource (Col1, Col2, Col3, Col4) Values(4,1,1,4)
Insert #tSource (Col1, Col2, Col3, Col4) Values(5,1,1,5)
Insert #tSource (Col1, Col2, Col3, Col4) Values(6,1,1,6)

--
-- Drop and Create a Temp Table to use as the "Destination" Table
--
IF OBJECT_ID('tempdb..#tDest') IS NOT NULL drop Table #tDest
create table #tDest (Col1 int, Col2 int, Col3 int, Col4 int)

--
-- Add all Rows from the Source to the Destination
--
Insert #tDest
Select Col1, Col2, Col3, Col4 from #tSource


--
-- Look at both tables to see that they are the same
--
select *
from #tSource
Select *
from #tDest

--
-- Make some changes to the Source
--
update #tSource
    Set Col3=19
    Where Col1=1
update #tSource
    Set Col3=29
    Where Col1=2
update #tSource
    Set Col2=38
    Where Col1=3
update #tSource
    Set Col2=48
    Where Col1=4

--
-- Look at the Differences
-- Note: Only 4 rows are different. 2 Rows have remained the same.
--
Select Col1, Col2, Col3, Col4
from #tSource
except
Select Col1, Col2, Col3, Col4
from #tDest

--
-- Update only the rows that have changed
-- Note: I am using Col1 like an ID column
--
Update #tDest
    Set Col2=S.Col2,
        Col3=S.Col3,
        Col4=S.Col4
From    (   Select Col1, Col2, Col3, Col4
            from #tSource
            except
            Select Col1, Col2, Col3, Col4
            from #tDest
        ) S
Where #tDest.Col1=S.Col1 

--
-- Look at the tables again to see that
--  the destination table has changed to match
--  the source table.

select *
from #tSource
Select *
from #tDest

--
-- Clean Up
--
drop table #tSource
drop table #tDest

1

はい、「無効な列」です。このエラーは「select company、stepid、fieldid、NewColumn from #Results」の行から発生しました。

t-sqlの実行には2つのフェーズがあります。

まず、解析、このフェーズでは、SQLサーバーは送信されたSQL文字列(テーブルの列を含む)の修正をチェックし、最高速の検索のためにクエリを最適化します。

次に、実行してデータを取得します。

テーブル#Resultsが存在する場合、解析プロセスは指定された列が有効かどうかをチェックします。そうでない場合(テーブルが存在しない)は、指定されたチェック列を渡して解析を行います。


0

一時テーブルの列を変更する場合は、クエリを再度実行する前にテーブルを削除する必要があります。(はい、それは迷惑です。あなたがしなければならないことだけです。)

これは、クエリが実行される前に「無効な列」のチェックがパーサーによって行われるため、ドロップされる前のテーブルの列に基づいているためです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.