Kiểm tra nếu một bảng tạm thời tồn tại và xóa nếu nó tồn tại trước khi tạo một bảng tạm thời


661

Tôi đang sử dụng đoạn mã sau để kiểm tra xem bảng tạm thời có tồn tại không và thả bảng nếu nó tồn tại trước khi tạo lại. Nó hoạt động tốt miễn là tôi không thay đổi các cột. Nếu tôi thêm một cột sau, nó sẽ báo lỗi "cột không hợp lệ". Xin vui lòng cho tôi biết những gì tôi đang làm sai.

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

Bạn đang thêm cột ở đâu? bạn có thể gửi mã chính xác gây ra lỗi cho bạn không?
Macros

Tôi đang thêm cột vào bảng #Results. Nếu bạn sao chép mã trên và chạy lần đầu tiên, bạn sẽ không gặp bất kỳ lỗi nào. Bây giờ nếu bạn thêm một cột vào bảng tạm thời và thêm cột vào câu lệnh chọn, nó sẽ nói cột không được tìm thấy (hoặc đại loại như thế).
Sridhar

22
Xem xét sử dụng mẫu sau : BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT. Nếu giao dịch thành công, bảng sẽ bị xóa. Nếu thất bại, bảng cũng sẽ biến mất (vì nó được tạo trong giao dịch). Trong mọi trường hợp: Không cần kiểm tra xem bảng đã tồn tại chưa.
Heinzi

1
Có vẻ như bạn chỉ cần báo cáo GO.
sam yi

Câu trả lời:


732

Tôi không thể tái tạo lỗi.

Có lẽ tôi không hiểu vấn đề.

Phần sau hoạt động tốt với tôi trong SQL Server 2005, với cột "foo" bổ sung xuất hiện trong kết quả chọn thứ hai:

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
NẾU OBJECT_ID ('tempdb .. # Kết quả') KHÔNG PHẢI NULL DROP BẢNG # Kết quả` TẠO BẢNG #Results (Công ty CHAR (3), StepId INT) chọn công ty, bước từ #results bây giờ quay lại câu lệnh tạo và thêm cột fieldid ở end.change chọn câu lệnh để bao gồm fieldid và chạy nó.
Sridhar

28
'tempdb..#name'chính xác là những gì tôi cần. Tôi đã sử dụng 'dbo.#name', như một kẻ ngốc. Tôi nhận được tempdbmột phần, nhưng những gì với dấu chấm đôi?
Conrad.Dean

77
@ Conrad.Dean dấu chấm kép là tên viết tắt của .dbo.
deutschZuid

32
@deutschZuid chính xác hơn khi nói rằng dấu chấm kép là lược đồ mặc định của người dùng, thường là dbo (không phải là ý tưởng hay, biến dbo thành lược đồ mặc định cho người dùng nhưng thường là như vậy)
jcollum

8
Mã của bạn rất khác so với OP, đến mức câu lệnh 'không thể sao chép' của bạn là vô nghĩa. Tôi mừng cho bạn rằng bạn đã làm cho nó hoạt động theo một cách khác.
Gerard ONeill

85

Tuyên bố nên theo thứ tự

  1. Thay đổi tuyên bố cho bảng
  2. ĐI
  3. Chọn câu lệnh.

Nếu không có 'GO' ở giữa, toàn bộ nội dung sẽ được coi là một tập lệnh duy nhất và khi câu lệnh chọn tìm cột, nó sẽ không được tìm thấy.

Với 'GO', nó sẽ coi một phần của tập lệnh lên đến 'GO' là một lô duy nhất và sẽ thực thi trước khi truy vấn sau 'GO'.


7
Điều này nên được đánh dấu là câu trả lời chính xác. Không phải là CHỌN thực sự sẽ chạy trước bảng tạo, Nó đang bị phân tích cú pháp và gây ra lỗi trước khi chạy, bởi vì có một bảng hiện có tên là #Results chưa có cột FieldId tại thời gian câu lệnh chọn được phân tích cú pháp. Thêm một GO trong đó sẽ tách truy vấn thành các đợt, mỗi đợt được phân tích cú pháp & chạy riêng.
Davos

2
Tôi không thể tin được sự chênh lệch về số phiếu giữa câu trả lời này và câu trả lời hàng đầu, đã thay đổi mã rất nhiều - mà không giải thích lý do - rằng nó vô nghĩa như một phản hồi.
underscore_d

63

Thay vì droppingvà tạo lại bảng tạm thời, bạn có thể truncatevà sử dụng lại nó

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

Nếu bạn đang sử dụng Sql Server 2016hoặc Azure Sql Databasesau đó sử dụng cú pháp dưới đây để thả bảng tạm thời và tạo lại nó. Thêm thông tin ở đây MSDN

Cú pháp

BẢNG DROP [NẾU EXISTS] [cơ sở dữ liệu. [giản lược tên]. | lược đồ tên. ] tên_bảng [, ... n]

Truy vấn:

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

Có vẻ như truncate/reusephương pháp này sẽ hiệu quả hơn so với DROP TABLE IF EXISTStrên Sql Server 2016Azure Sql Databaselà tốt. đây không phải là trường hợp?
JDawg

@prdp Tại sao bạn đề xuất DROP TABLE IF Existscho SQL 2016 hoặc Azure? Cú pháp có sẵn bắt đầu từ SQL 2008. Xem liên kết MSDN trong câu trả lời của bạn? Yếu tố hiệu suất?
HappyTown

4
Đừng bận tâm. Bây giờ tôi nhận ra, DROP TABLEđược hỗ trợ từ SQL Server 2008, nhưng IF EXISTSđiều khoản đã được giới thiệu vào năm 2016.
HappyTown

1
Tôi sử dụng INTO: chọn * INTO #HistoricoUserTable từ dbo.HistoricoUser
Kiquenet

54

Tôi nghĩ vấn đề là bạn cần thêm câu lệnh GO ở giữa để tách việc thực thi thành các đợt. Vì tập lệnh thả thứ hai tức là IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Resultskhông bỏ bảng tạm thời là một phần của lô đơn. Bạn có thể vui lòng thử đoạn script dưới đây.

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
Chú ý; tempdb..trong đoạn mã trên là rất quan trọng. Nó cần phải đặt trước tên bảng tạm thời của bạn. Đơn giản chỉ cần kiểm tra OBJECT_ID('#Results')là không đủ. Các bảng tạm thời được lưu trữ trong cơ sở dữ liệu TempDB. Theo Microsoft: Cơ sở dữ liệu hệ thống TempDB là tài nguyên toàn cầu có sẵn cho tất cả người dùng được kết nối với phiên bản SQL Server hoặc được kết nối với Cơ sở dữ liệu SQL
iCode

Cảm ơn, @iCode. Đó là chìa khóa để loại bỏ các bảng tạm thời: nó phải được thực hiện tempdbhoặc nó sẽ không biến mất.
Alex

37

Điều này có thể được thực hiện với một dòng mã:

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

1
tôi phải xem xét điều này mỗi ngày
Ab Bennett

28

Điều này làm việc cho tôi: 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
Đây chỉ là cú pháp khác nhau cho việc thả bảng có điều kiện. Điều đó thú vị nhưng không giải quyết được câu hỏi của OP và hầu hết trong số đó là dư thừa. Nếu bạn chỉ kiểm tra OBJECT_ID (N'tempdb .. # Kết quả ') không phải là null thì điều đó đủ để chứng minh rằng đối tượng đã tồn tại.
Davos

21

Chỉ cần một nhận xét nhỏ từ phía tôi vì OBJECT_IDnó không làm việc cho tôi. Nó luôn trả về

`#tempTable không tồn tại

..even mặc dù nó không tồn tại. Tôi chỉ thấy nó được lưu trữ với tên khác (được đặt trước bởi _dấu gạch dưới) như vậy:

#tempTable________

Công việc này tốt cho tôi:

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

6
Thận trọng: Mã đó sẽ phát hiện một bảng nếu nó được tạo bởi bất kỳ luồng nào. Các bảng # temp đơn được tạo riêng cho mỗi luồng / người gọi đến một Proc được lưu trữ, đó là lý do tại sao các dấu gạch dưới trong tên để một bản sao khác nhau tồn tại trên mỗi luồng / tiến trình. Object_ID sẽ hoạt động tốt đối với luồng hiện tại, miễn là bạn đang sử dụng SQL 2005 trở lên.
Bytemaster

12

Bây giờ bạn có thể sử dụng cú pháp dưới đây nếu bạn đang sử dụng một trong các phiên bản mới của SQL Server (2016+).

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

1
Tôi đang sử dụng SSMS 17.3 và điều này mang lạiIncorrect syntax near the keyword 'IF'.
StingyJack

7
@StingyJack Vì SQL Syntax không liên quan đến phiên bản SSMS, mà là phiên bản SQL Server liên quan. Điều IF [NOT] EXISTSkhoản có sẵn từ SQL Server 2016. Không quan trọng bạn đang sử dụng phiên bản SSMS nào.
Pred

10

pmac72 đang sử dụng GO để chia truy vấn thành các đợt và sử dụng ALTER.

Bạn dường như đang chạy cùng một đợt nhưng chạy hai lần sau khi thay đổi: DROP ... TẠO ... chỉnh sửa ... DROP ... TẠO ..

Có lẽ gửi mã chính xác của bạn để chúng tôi có thể thấy những gì đang xảy ra.


7

Tôi thường gặp lỗi này khi tôi đã tạo bảng tạm thời; mã kiểm tra câu lệnh SQL để tìm lỗi sẽ thấy bảng tạm thời "cũ" và trả về số lượng sai trong số cột trong các câu lệnh sau, như thể bảng tạm thời không bao giờ bị hủy.

Sau khi thay đổi số lượng cột trong bảng tạm thời sau khi đã tạo phiên bản có ít cột hơn, hãy thả bảng và THEN chạy truy vấn của bạn.


6

Gần đây tôi đã thấy một DBA làm một cái gì đó tương tự như thế này:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)

2
Câu lệnh thử này sẽ bắt các lỗi khác có thể xảy ra khi cố gắng thả bảng. Mã này giả định rằng lý do duy nhất để thử sẽ thất bại là vì bảng không tồn tại. Nó có thể sẽ làm việc hầu hết thời gian, nhưng tôi sẽ không đảm bảo điều đó. Nếu câu lệnh thử không thành công vì một số lý do khác, bạn sẽ gặp lỗi khi tạo bảng, vì điều này đã che giấu vấn đề thực sự với việc làm rơi bảng.
Davos

Điều này hiệu quả nhưng thật tệ, tôi không khuyến khích một cách khó khăn khi có giải pháp thông minh và hoàn hảo. Và ngoài ra, mặc dù OP đã chỉ định phiên bản 2005, nhưng khối thử bắt không được hỗ trợ trong các phiên bản cũ hơn
dejjub-AIS

Vấn đề khác với điều này là hệ tư tưởng sử dụng try / Catch vs logic. Bạn có thể xem chi tiết của các cuộc tranh luận ở đây: stackoverflow.com/questions/17335217/try-catch-or-if-statement/...
logixologist

3

Mã của tôi sử dụng Sourcebảng thay đổi và Destinationbảng phải khớp với những thay đổi đó.

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

Có, "cột không hợp lệ" lỗi này xuất phát từ dòng "chọn công ty, stepid, fieldid, NewColumn từ #Results".

Có hai giai đoạn chạy t-sql,

đầu tiên, phân tích cú pháp, trong giai đoạn này, máy chủ sql kiểm tra sự điều chỉnh của chuỗi sql bạn đã gửi, bao gồm cả cột của bảng và tối ưu hóa truy vấn của bạn để truy xuất nhanh nhất.

thứ hai, chạy, truy xuất lại các dữ liệu.

Nếu bảng #Results tồn tại thì quá trình phân tích cú pháp sẽ kiểm tra các cột bạn đã chỉ định có hợp lệ hay không, phân tích cú pháp khác (bảng không tồn tại) sẽ được chuyển qua các cột kiểm tra như bạn đã chỉ định.


0

Khi bạn thay đổi một cột trong bảng tạm thời, bạn phải bỏ bảng trước khi chạy lại truy vấn. (Vâng, thật khó chịu. Chỉ là những gì bạn phải làm.)

Tôi luôn cho rằng điều này là do kiểm tra "cột không hợp lệ" được thực hiện bởi trình phân tích cú pháp trước khi truy vấn được chạy, do đó, nó dựa trên các cột trong bảng trước khi nó bị hủy ..... và đó là những gì pnbs cũng nói.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.