ตรวจสอบว่ามีตารางชั่วคราวและลบหากมีอยู่ก่อนสร้างตารางชั่วคราว


662

ฉันใช้รหัสต่อไปนี้เพื่อตรวจสอบว่ามีตารางชั่วคราวอยู่หรือไม่และวางตารางหากมีอยู่ก่อนสร้างอีกครั้ง มันทำงานได้ดีตราบใดที่ฉันไม่เปลี่ยนคอลัมน์ หากฉันเพิ่มคอลัมน์ในภายหลังมันจะให้ข้อผิดพลาดว่า "คอลัมน์ไม่ถูกต้อง" โปรดแจ้งให้เราทราบว่าฉันทำอะไรผิด

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 หากคุณคัดลอกโค้ดด้านบนและเรียกใช้เป็นครั้งแรกคุณจะไม่ได้รับข้อผิดพลาดใด ๆ ตอนนี้ถ้าคุณเพิ่มคอลัมน์ในตาราง temp และเพิ่มคอลัมน์ลงในคำสั่ง select มันจะพูดว่าไม่พบคอลัมน์ (หรืออะไรทำนองนั้น)
Sridhar

22
BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMITพิจารณาการใช้รูปแบบต่อไปนี้: หากการทำธุรกรรมสำเร็จตารางจะถูกลบออก หากล้มเหลวตารางจะหายไปเช่นกัน (เนื่องจากสร้างขึ้นภายในธุรกรรม) ไม่ว่าในกรณีใด: ไม่จำเป็นต้องตรวจสอบว่ามีตารางอยู่แล้ว
Heinzi

1
ดูเหมือนว่าคุณจะต้องมีคำสั่ง GO
sam yi

คำตอบ:


733

ฉันไม่สามารถทำซ้ำข้อผิดพลาด

บางทีฉันไม่เข้าใจปัญหา

งานต่อไปนี้ใช้ได้สำหรับฉันใน SQL Server 2005 โดยมีคอลัมน์ "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') ไม่ใช่ NULL DROP Table # Results` CREATE TABLE #Results (CHAR บริษัท (3), INT StepId INT) เลือก บริษัท , stepid จาก #results กลับไปที่คำสั่ง create และเพิ่ม a คอลัมน์ fieldid ที่ end.change เลือกคำสั่งเพื่อรวม fieldid และเรียกใช้
Sridhar

28
'tempdb..#name'เป็นสิ่งที่ฉันต้องการ ฉันใช้'dbo.#name'เหมือนคนโง่ ฉันได้tempdbส่วนแล้ว แต่มีจุดสองจุดคืออะไร
Conrad.Dean

77
@ Conrad.Dean double dot เป็นตัวย่อของ. dbo
deutschZuid

32
@deutschZuid มีความแม่นยำมากกว่าที่จะบอกว่าจุดสองจุดเป็นแบบแผนเริ่มต้นของผู้ใช้ซึ่งโดยทั่วไปจะเป็น dbo (ซึ่งไม่ใช่ความคิดที่ดีทำให้ dbo เป็นแบบแผนเริ่มต้นสำหรับผู้ใช้ แต่นั่นเป็นวิธีปกติ)
jcollum

8
รหัสของคุณแตกต่างจาก OP ซึ่งข้อความ 'ไม่สามารถทำซ้ำ' ของคุณนั้นไม่มีความหมาย ฉันมีความสุขสำหรับคุณที่คุณได้รับมันไปทำงานที่แตกต่างกัน
เจอราร์ดโอนีล

85

คำสั่งควรเป็นของการสั่งซื้อ

  1. แก้ไขคำสั่งสำหรับตาราง
  2. ไป
  3. เลือกคำสั่ง

หากไม่มี 'GO' อยู่ระหว่างสิ่งทั้งหมดจะถูกพิจารณาเป็นสคริปต์เดียวและเมื่อคำสั่ง select ค้นหาคอลัมน์จะไม่พบ

ด้วย 'GO' มันจะพิจารณาส่วนของสคริปต์จนถึง 'GO' เป็นชุดเดียวและจะดำเนินการก่อนที่จะเข้าสู่คิวรีหลังจาก 'GO'


7
ควรทำเครื่องหมายเป็นคำตอบที่ถูกต้อง ไม่ใช่ว่า SELECT กำลังจะทำงานก่อนที่จะสร้างตาราง แต่จะถูกแยกวิเคราะห์และโยนข้อผิดพลาดก่อนที่จะถูกเรียกใช้เนื่องจากมีตารางที่มีอยู่ชื่อ #Results ที่ยังไม่มีคอลัมน์ FieldId ที่ เวลาที่คำสั่ง select ถูกวิเคราะห์คำ การเพิ่ม GO เข้าไปในนั้นจะแยกคิวรีออกเป็นแบตช์ซึ่งแต่ละการแยกวิเคราะห์ & รันแยกกัน
Davos

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 2016หรือAzure Sql Databaseใช้ไวยากรณ์ด้านล่างเพื่อวางตาราง temp และสร้างใหม่ ข้อมูลเพิ่มเติมที่นี่MSDN

วากยสัมพันธ์

DROP Table [IF EXISTS] [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 EXISTSในSql Server 2016และAzure Sql Databaseเช่นกัน นี่ไม่ใช่กรณีหรือไม่
JDawg

@prdp ทำไมคุณแนะนำDROP TABLE IF ExistsSQL 2016 หรือ Azure ไวยากรณ์พร้อมใช้งานเริ่มตั้งแต่ SQL 2008 ดูลิงก์ MSDN ในคำตอบของคุณ? ปัจจัยด้านประสิทธิภาพ?
HappyTown

4
ไม่เป็นไร. ฉันรู้แล้วว่าตอนนี้ได้DROP TABLEรับการสนับสนุนจาก SQL Server 2008 แต่IF EXISTSได้เปิดใช้คำสั่งในปี 2559
HappyTown

1
ฉันใช้INTO: select * INTO #HistoricoUserTable จาก dbo.HistoricoUser
Kiquenet

54

ฉันคิดว่าปัญหาคือคุณต้องเพิ่มคำสั่ง GO ในระหว่างเพื่อแยกการดำเนินการเป็นชุด ในฐานะที่เป็นสคริปต์วางที่สองคือ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..ในรหัสข้างต้นเป็นสิ่งสำคัญมาก มันจะต้องนำหน้าชื่อตาราง temp ของคุณ เพียงแค่ตรวจสอบOBJECT_ID('#Results')ไม่เพียงพอ ตารางชั่วคราวจะถูกเก็บไว้ในฐานข้อมูล TempDB สำหรับ Microsoft: ฐานข้อมูลระบบ TempDB เป็นทรัพยากรทั่วโลกที่ผู้ใช้ทุกคนเชื่อมต่อกับ SQL Server หรือเชื่อมต่อกับฐานข้อมูล SQL
iCode

ขอบคุณ @iCode นั่นคือกุญแจสำคัญสำหรับการวางตาราง temp: มันจะต้องมีการทำใน tempdbหรือจะไม่หายไป
อเล็กซ์

37

สามารถทำได้ด้วยรหัสบรรทัดเดียว:

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 ') นั้นไม่เป็นค่าว่างนั่นก็เพียงพอที่จะพิสูจน์ว่าวัตถุนั้นมีอยู่แล้ว
Davos

21

เพียงความเห็นเล็กน้อยจากด้านข้างของฉันเพราะมันใช้OBJECT_IDไม่ได้สำหรับฉัน มันกลับมาเสมอ

`#tempTable ไม่มีอยู่จริง

.. แม้จะมีอยู่จริง ฉันเพิ่งพบว่ามีการจัดเก็บชื่ออื่น (postfixed โดย_underscores) เช่น:

#tempTable________

มันใช้งานได้ดีสำหรับฉัน:

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

6
ข้อควรระวัง: รหัสนั้นจะตรวจจับตารางหากมันถูกสร้างขึ้นโดยกระทู้ใด ๆ ตาราง # temp เดี่ยวถูกสร้างแยกต่างหากต่อเธรด / ผู้เรียกไปยัง proc ที่จัดเก็บซึ่งเป็นสาเหตุที่ขีดล่างในชื่อเพื่อให้สำเนาที่แตกต่างกันมีอยู่ต่อเธรด / กระบวนการ 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 เวอร์ชันใด
Pred

10

pmac72ใช้ GO เพื่อแยกย่อยแบบสอบถามเป็นชุดและใช้ ALTER

ดูเหมือนว่าคุณจะเรียกใช้ชุดเดียวกัน แต่เรียกใช้สองครั้งหลังจากเปลี่ยนเป็น: DROP ... CREATE ... แก้ไข ... DROP ... CREATE ..

บางทีโพสต์รหัสที่แน่นอนของคุณเพื่อให้เราสามารถเห็นสิ่งที่เกิดขึ้น


7

ฉันมักจะพบข้อผิดพลาดนี้เมื่อฉันได้สร้างตารางชั่วคราวแล้ว รหัสที่ตรวจสอบคำสั่ง SQL เพื่อหาข้อผิดพลาดจะเห็นตาราง temp "old" ในตำแหน่งและส่งคืน miscount กับจำนวนคอลัมน์ในคำสั่งภายหลังจากนั้นราวกับว่าตาราง temp ไม่เคยถูกทิ้ง

หลังจากเปลี่ยนจำนวนคอลัมน์ในตารางชั่วคราวหลังจากสร้างเวอร์ชันที่มีคอลัมน์น้อยลงแล้วให้วางตารางจากนั้นเรียกใช้คิวรีของคุณ


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
คำสั่งลองนี้จะจับข้อผิดพลาดอื่น ๆ ที่อาจเกิดขึ้นเมื่อพยายามที่จะวางตาราง รหัสนี้อนุมานว่าเหตุผลเดียวที่ทำให้การลองล้มเหลวเป็นเพราะไม่มีตาราง มันอาจจะใช้เวลาส่วนใหญ่ แต่ฉันจะไม่รับประกัน หากคำสั่งลองล้มเหลวด้วยเหตุผลอื่นคุณจะได้รับข้อผิดพลาดเมื่อสร้างตารางเนื่องจากสิ่งนี้ได้หลอกลวงปัญหาจริงด้วยการวางตาราง
Davos

ใช้งานได้ แต่แย่ฉันไม่สนับสนุนวิธียากเมื่อมีวิธีแก้ไขปัญหาที่ชาญฉลาดและสมบูรณ์แบบ และถึงแม้จะใช้ OP 2005 รุ่นที่ระบุไว้ลองใช้ catch catch ไม่รองรับในรุ่นเก่า
dejjub-AIS

ปัญหาอื่น ๆ ของเรื่องนี้คืออุดมการณ์ของการใช้ลอง / จับกับตรรกะ คุณสามารถดูการอภิปรายเพิ่มเติมได้ที่นี่: 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

ใช่ "คอลัมน์ที่ไม่ถูกต้อง" ข้อผิดพลาดนี้ยกมาจากบรรทัด "เลือก บริษัท , stepid, fieldid, NewColumn จาก #Results"

มีสองขั้นตอนในการรัน t-sql

อันดับแรกการแยกวิเคราะห์ในเฟสนี้เซิร์ฟเวอร์ sql ตรวจสอบการแก้ไขของคุณที่ส่งสตริง sql รวมถึงคอลัมน์ของตารางและปรับการค้นหาของคุณให้เร็วที่สุดเพื่อการเรียกคืนที่เร็วที่สุด

วินาทีเรียกใช้เรียกคืนข้อมูล

หากตาราง #Results มีอยู่แล้วกระบวนการแยกวิเคราะห์จะตรวจสอบคอลัมน์ที่คุณระบุว่าถูกต้องหรือไม่มิฉะนั้น (ไม่มีตาราง) จะแยกวิเคราะห์โดยผ่านคอลัมน์ตรวจสอบตามที่คุณระบุ


0

เมื่อคุณเปลี่ยนคอลัมน์ในตารางชั่วคราวคุณต้องวางตารางก่อนที่จะเรียกใช้แบบสอบถามอีกครั้ง (ใช่มันน่ารำคาญสิ่งที่คุณต้องทำ)

ฉันคิดเสมอว่านี่เป็นเพราะการตรวจสอบ "คอลัมน์ที่ไม่ถูกต้อง" จะดำเนินการโดยตัวแยกวิเคราะห์ก่อนที่จะเรียกใช้แบบสอบถามดังนั้นจึงขึ้นอยู่กับคอลัมน์ในตารางก่อนที่จะถูกลบ ..... และนั่นคือสิ่งที่ pnbs กล่าวด้วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.