Periksa apakah tabel sementara ada dan hapus jika ada sebelum membuat tabel sementara

663

Saya menggunakan kode berikut untuk memeriksa apakah tabel sementara ada dan drop tabel jika ada sebelum membuat lagi. Ini berfungsi dengan baik selama saya tidak mengubah kolom. Jika saya menambahkan kolom nanti, itu akan memberikan kesalahan mengatakan "kolom tidak valid". Tolong beri tahu saya apa yang saya lakukan salah.

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
Sridhar
sumber
Di mana Anda menambahkan kolom? dapatkah Anda memposting kode persis yang memberi Anda kesalahan?
Macro
Saya menambahkan kolom ke tabel #Hasil. Jika Anda menyalin kode di atas dan menjalankannya untuk pertama kali Anda tidak mendapatkan kesalahan. Sekarang jika Anda menambahkan kolom ke tabel temp dan menambahkan kolom ke pernyataan pilih, itu akan mengatakan kolom tidak ditemukan (atau sesuatu seperti itu).
Sridhar
22
Pertimbangkan untuk menggunakan pola berikut: BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT. Jika transaksi berhasil, tabel akan dihapus. Jika gagal, tabel akan hilang juga (karena dibuat dalam transaksi). Dalam hal apa pun: Tidak perlu memeriksa apakah tabel sudah ada.
Heinzi
1
Sepertinya Anda hanya perlu pernyataan GO.
sam yi

Jawaban:

734

Saya tidak dapat mereproduksi kesalahan.

Mungkin saya tidak mengerti masalahnya.

Berikut ini berfungsi dengan baik untuk saya di SQL Server 2005, dengan kolom "foo" tambahan muncul di hasil pilih kedua:

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
pmac72
sumber
1
JIKA OBJECT_ID ('tempdb .. # Hasil') BUKAN NULL DROP TABLE # Hasil` CREATE TABLE #Hasil (Company CHAR (3), StepId INT) pilih perusahaan, stepid dari #result sekarang kembali ke membuat pernyataan dan menambahkan kolom fieldid di end.change pilih pernyataan untuk memasukkan fieldid dan jalankan.
Sridhar
28
'tempdb..#name'persis apa yang saya butuhkan. Saya menggunakan 'dbo.#name', seperti orang bodoh. Saya mendapatkan tempdbbagiannya, tetapi ada apa dengan titik ganda?
Conrad.Dean
77
@ Conrad.Dean double dot adalah singkatan dari .dbo.
deutschZuid
32
@deutschZuid lebih akurat untuk mengatakan bahwa titik ganda adalah skema default pengguna, yang biasanya dbo (yang bukan ide bagus, menjadikan dbo skema default untuk pengguna tetapi biasanya begitulah)
jcollum
8
Kode Anda sangat berbeda dari OP, sehingga pernyataan 'tidak dapat direproduksi' tidak ada artinya. Saya senang untuk Anda karena Anda membuatnya bekerja dengan cara yang berbeda.
Gerard ONeill
85

Pernyataan harus sesuai urutan

  1. Ubah pernyataan untuk tabel
  2. PERGILAH
  3. Pilih pernyataan.

Tanpa 'GO' di antaranya, semuanya akan dianggap sebagai satu skrip tunggal dan ketika pernyataan pilih mencari kolom, itu tidak akan ditemukan.

Dengan 'GO', itu akan mempertimbangkan bagian dari skrip hingga 'GO' sebagai satu batch tunggal dan akan dieksekusi sebelum masuk ke permintaan setelah 'GO'.

SDS
sumber
7
Ini harus ditandai sebagai jawaban yang benar. Bukannya SELECT benar-benar akan berjalan sebelum membuat tabel, itu yang sedang diurai dan melempar kesalahan sebelum dijalankan, karena ada tabel yang sudah ada yang disebut # Hasil yang belum memiliki kolom FieldId di waktu pernyataan pilih diuraikan. Menambahkan GO di sana memisahkan kueri menjadi batch, yang masing-masing diuraikan & dijalankan secara terpisah.
Davos
2
Saya tidak percaya perbedaan suara antara ini dan jawaban teratas, yang mengubah kode begitu banyak - tanpa menjelaskan mengapa - bahwa itu tidak ada artinya sebagai tanggapan.
underscore_d
63

Alih-alih droppingdan menciptakan kembali tabel temp yang Anda bisa truncatedan menggunakannya kembali

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

Jika Anda menggunakan Sql Server 2016atau Azure Sql Databasekemudian menggunakan sintaks di bawah ini untuk menjatuhkan tabel temp dan membuatnya kembali. Info lebih lanjut di sini MSDN

Sintaksis

DROP TABEL [JIKA ADA] [database_name. [schema_name]. | schema_name. ] table_name [, ... n]

Pertanyaan:

DROP TABLE IF EXISTS tempdb.dbo.#Results
CREATE TABLE #Results
  (
   Company             CHAR(3),
   StepId              TINYINT,
   FieldId             TINYINT,
  )
P ரதீப்
sumber
Tampaknya truncate/reusemetode ini akan lebih efisien daripada yang DROP TABLE IF EXISTSaktif Sql Server 2016dan Azure Sql Databasejuga. Bukankah ini masalahnya?
JDawg
@prdp Mengapa Anda menyarankan DROP TABLE IF Existsuntuk SQL 2016 atau Azure? Sintaks tersedia mulai SQL 2008. Lihat tautan MSDN di jawaban Anda? Faktor kinerja?
HappyTown
4
Sudahlah. Saya sekarang menyadari, DROP TABLEdidukung dari SQL Server 2008, tetapi IF EXISTSklausa ini diperkenalkan pada 2016.
HappyTown
1
Saya menggunakan INTO: pilih * KE #HistoricoUserTable dari dbo.HistoricoUser
Kiquenet
54

Saya pikir masalahnya adalah Anda perlu menambahkan pernyataan GO di antara untuk memisahkan eksekusi menjadi batch. Sebagai skrip drop kedua yaitu IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Resultstidak menjatuhkan tabel temp menjadi bagian dari batch tunggal. Bisakah Anda mencoba skrip di bawah ini.

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
vikas
sumber
1
Dari catatan; tempdb..dalam kode di atas sangat penting. Perlu mendahului nama tabel temp Anda. Cukup mengecek saja OBJECT_ID('#Results')tidak cukup. Tabel sementara disimpan di database TempDB. Per Microsoft: Basis data sistem TempDB adalah sumber daya global yang tersedia untuk semua pengguna yang terhubung ke instance dari SQL Server atau terhubung ke Database SQL
iCode
Terima kasih, @iCode. Itulah kunci untuk menjatuhkan tabel temp: harus dilakukan tempdbatau tidak akan hilang.
Alex
37

Ini dapat dilakukan dengan satu baris kode:

IF OBJECT_ID('tempdb..#tempTableName') IS NOT NULL DROP TABLE #tempTableName;   
S Krishna
sumber
1
Saya harus melihat ini setiap hari
Ab Bennett
28

Ini bekerja untuk saya: 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;
pengguna219628
sumber
1
Ini hanya sintaks yang berbeda untuk penurunan tabel bersyarat. Ini menarik tetapi tidak menyelesaikan pertanyaan OP, dan sebagian besar berlebihan. Jika Anda baru saja memeriksa OBJECT_ID (N'tempdb .. # Hasil ') tidak nol maka itu cukup untuk membuktikan bahwa objek sudah ada.
Davos
21

Hanya sedikit komentar dari pihak saya karena OBJECT_IDtidak berhasil untuk saya. Itu selalu mengembalikan itu

`#tempTable tidak ada

..even meskipun tidak eksis. Saya baru saja menemukan itu disimpan dengan nama yang berbeda (postfixed oleh _garis bawah) seperti:

#tempTable________

Ini bekerja dengan baik untuk saya:

IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#tempTable%') BEGIN
   DROP TABLE #tempTable;
END;
Ivan Sivak
sumber
6
Perhatian: Kode itu akan mendeteksi tabel jika itu dibuat oleh utas apa pun. Tabel temp # tunggal dibuat secara terpisah per utas / penelepon ke proc tersimpan, itulah sebabnya garis bawah dalam nama sehingga salinan yang berbeda ada per utas / proses. Object_ID harus berfungsi ok untuk utas saat ini, selama Anda menggunakan SQL 2005 atau yang lebih baru.
Bytemaster
12

Sekarang Anda dapat menggunakan sintaks di bawah ini jika Anda menggunakan salah satu versi baru dari SQL Server (2016+).

DROP TABLE IF EXISTS schema.yourtable(even temporary tables #...)
Othman Dahbi-Skali
sumber
1
Saya menggunakan SSMS 17.3 dan ini memberiIncorrect syntax near the keyword 'IF'.
StingyJack
7
@ StingyJack Karena Sintaks SQL tidak terkait versi SSMS, tetapi terkait versi SQL Server. The IF [NOT] EXISTSklausul tersedia dari SQL Server 2016. Tidak peduli versi yang SSMS Anda gunakan.
Pred
10

pmac72 menggunakan GO untuk memecah kueri menjadi batch dan menggunakan ALTER.

Anda tampaknya menjalankan batch yang sama tetapi menjalankannya dua kali setelah mengubahnya: DROP ... CREATE ... edit ... DROP ... CREATE ..

Mungkin memposting kode persis Anda sehingga kami dapat melihat apa yang sedang terjadi.

gbn
sumber
7

Saya biasanya menemukan kesalahan ini ketika saya sudah membuat tabel temp; kode yang memeriksa pernyataan SQL untuk kesalahan melihat tabel temp "lama" di tempat dan mengembalikan salah hitung pada jumlah kolom dalam pernyataan kemudian, seolah-olah tabel temp tidak pernah dijatuhkan.

Setelah mengubah jumlah kolom dalam tabel temp setelah membuat versi dengan lebih sedikit kolom, letakkan tabel dan MAKA jalankan kueri Anda.

Jacob Griffin
sumber
6

Saya baru-baru ini melihat DBA melakukan sesuatu yang mirip dengan ini:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)
anonxen
sumber
2
Pernyataan coba ini akan menangkap kesalahan lain yang bisa terjadi ketika mencoba menjatuhkan tabel. Kode ini mengasumsikan bahwa satu-satunya alasan percobaan gagal adalah karena tabel tidak ada. Mungkin akan bekerja sebagian besar waktu, tetapi saya tidak akan menjaminnya. Jika pernyataan coba gagal karena alasan lain, Anda akan mendapatkan kesalahan saat membuat tabel, karena ini telah menutupi masalah sebenarnya dengan menjatuhkan tabel.
Davos
Ini bekerja tetapi buruk saya tidak mendorong dengan cara yang sulit ketika ada solusi cerdas dan sempurna ada di sana. Dan juga, meskipun OP menentukan versi 2005, coba tangkap blok tidak didukung di versi yang lebih lama
dejjub-AIS
Masalah lain dengan ini adalah ideologi menggunakan try / catch vs logic. Anda dapat melihat lebih banyak dari perdebatan di sini: stackoverflow.com/questions/17335217/try-catch-or-if-statement/…
logixologist
3

Kode saya menggunakan Sourcetabel yang berubah, dan Destinationtabel yang harus cocok dengan perubahan itu.

-- 
-- 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
Mike Lewis
sumber
1

Ya, "kolom tidak valid" kesalahan ini muncul dari baris "pilih perusahaan, stepid, fieldid, Kolom Baru dari #Hasil".

Ada dua fase menjalankan t-sql,

pertama, parsing, dalam fase ini server sql memeriksa koreksi dari Anda mengirimkan string sql, termasuk kolom tabel, dan dioptimalkan permintaan Anda untuk retreival tercepat.

kedua, menjalankan, menerima kembali data.

Jika tabel #Hasil ada maka proses penguraian akan memeriksa kolom yang Anda tentukan valid atau tidak, jika tidak (tabel tidak ada) penguraian akan dengan melewati kolom pemeriksaan seperti yang Anda tentukan.

pnbps
sumber
0

Saat Anda mengubah kolom di tabel temp, Anda harus menjatuhkan tabel sebelum menjalankan kueri lagi. (Ya, itu menjengkelkan. Hanya apa yang harus Anda lakukan.)

Saya selalu berasumsi ini karena pemeriksaan "kolom tidak valid" dilakukan oleh parser sebelum kueri dijalankan, jadi didasarkan pada kolom dalam tabel sebelum dijatuhkan ..... dan itulah yang juga dikatakan pnbs.

Buruk
sumber