Sprawdź, czy istnieje tabela tymczasowa i usuń, jeśli istnieje, przed utworzeniem tabeli tymczasowej

662

Korzystam z następującego kodu, aby sprawdzić, czy istnieje tabela tymczasowa i upuścić tabelę, jeśli istnieje, przed ponownym utworzeniem. Działa dobrze, dopóki nie zmieniam kolumn. Jeśli dodam kolumnę później, wyświetli się komunikat „nieprawidłowa kolumna”. Daj mi znać, co robię źle.

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
źródło
Gdzie dodajesz kolumnę? czy możesz opublikować dokładny kod, który powoduje błąd?
Makra,
Dodaję kolumnę do tabeli #Results. Jeśli skopiujesz powyższy kod i uruchom go po raz pierwszy, nie pojawi się żaden błąd. Teraz, jeśli dodasz kolumnę do tabeli tymczasowej i dodasz kolumnę do instrukcji select, powiesz, że kolumna nie została znaleziona (lub coś podobnego).
Sridhar
22
Rozważmy następujący wzór za pomocą: BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT. Jeśli transakcja się powiedzie, tabela zostanie usunięta. Jeśli się nie powiedzie, tabela również zniknie (ponieważ została utworzona w ramach transakcji). W każdym razie: Nie trzeba sprawdzać, czy tabela już istnieje.
Heinzi
1
Wygląda na to, że potrzebujesz tylko instrukcji GO.
sam yi

Odpowiedzi:

733

Nie mogę odtworzyć błędu.

Być może nie rozumiem problemu.

Poniższe działa dla mnie dobrze w SQL Server 2005, z dodatkową kolumną „foo” pojawiającą się w drugim wyniku wyboru:

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
źródło
1
JEŚLI IDENTYFIKATOR OBIEKTU ('tempdb .. # Wyniki') NIE JEST NULL DROP TABELA # wyniki``TWÓRZ TABELĘ # Wyniki (Firma CHAR (3), StepId INT) wybierz firmę, stepid z #results teraz wróć do instrukcji tworzenia i dodaj kolumna identyfikator pola na końcu. zmień instrukcję, aby dołączyć identyfikator pola i uruchomić go.
Sridhar
28
'tempdb..#name'jest dokładnie tym, czego potrzebowałem. Używałem 'dbo.#name', jak głupiec. Rozumiem tempdb, ale co z podwójnymi kropkami?
Conrad.Dean
77
@ Conrad.Dean double dot to skrót od .dbo.
deutschZuid
32
@deutschZuid dokładniej jest powiedzieć, że podwójna kropka jest domyślnym schematem użytkownika, którym zwykle jest dbo (co nie jest
dobrym
8
Twój kod jest tak różny od OP, że twoje stwierdzenie „nie można odtworzyć” jest bez znaczenia. Cieszę się, że działasz inaczej.
Gerard ONeill
85

Oświadczenie powinno być uporządkowane

  1. Instrukcja Alter dla tabeli
  2. UDAĆ SIĘ
  3. Wybierz wyciąg.

Bez „GO” pomiędzy nimi, całość będzie traktowana jako pojedynczy skrypt, a kiedy instrukcja select szuka kolumny, nie zostanie znaleziona.

W przypadku „GO” rozważy część skryptu aż do „GO” jako pojedynczą partię i wykona się, zanim przejdzie do zapytania po „GO”.

SDS
źródło
7
To powinno być oznaczone jako poprawna odpowiedź. To nie jest tak, że SELECT faktycznie uruchomi się przed utworzeniem tabeli, ale to, że jest analizowany i generuje błąd przed uruchomieniem, ponieważ istnieje istniejąca tabela o nazwie #Results, która nie ma jeszcze kolumny FieldId w czas parsowania instrukcji select. Dodanie GO rozdziela zapytanie na partie, które są analizowane i uruchamiane osobno.
Davos,
2
Nie mogę uwierzyć w rozbieżność głosów między tą a najwyższą odpowiedzią, która tak bardzo zmieniła kod - bez wyjaśnienia dlaczego - że była bez znaczenia jako odpowiedź.
underscore_d
63

Zamiast droppingtworzyć tabelę tymczasową truncatei ponownie ją tworzyć, możesz jej ponownie użyć

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

Jeśli używasz Sql Server 2016lub Azure Sql Databaseużyj poniższej składni, aby upuścić tabelę tymczasową i ponownie ją utworzyć. Więcej informacji tutaj MSDN

Składnia

DROP TABLE [JEŚLI ISTNIEJE] [nazwa_bazy_danych. [nazwa_schematu]. | nazwa_schematu. ] nazwa_tabeli [, ... n]

Pytanie:

DROP TABLE IF EXISTS tempdb.dbo.#Results
CREATE TABLE #Results
  (
   Company             CHAR(3),
   StepId              TINYINT,
   FieldId             TINYINT,
  )
P ரதீப்
źródło
Wydaje się, że truncate/reusemetoda będzie bardziej wydajny niż DROP TABLE IF EXISTSna Sql Server 2016i Azure Sql Databasetak dobrze. Czy tak nie jest?
JDawg,
@prdp Dlaczego sugerujesz DROP TABLE IF Existsdla SQL 2016 lub Azure? Składnia jest dostępna począwszy od SQL 2008. Widzisz łącze MSDN w swojej odpowiedzi? Współczynnik wydajności?
HappyTown,
4
Nieważne. Teraz zdałem sobie sprawę, że DROP TABLEjest obsługiwany z SQL Server 2008, ale IF EXISTSklauzula została wprowadzona w 2016 roku.
HappyTown
1
Używam INTO: wybierz * INTO #HistoricoUserTable z dbo.HistoricoUser
Kiquenet
54

Myślę, że problem polega na tym, że musisz dodać instrukcję GO pomiędzy, aby rozdzielić wykonanie na partie. Jako drugi skrypt zrzutu, tj. IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #ResultsNie upuścił tabeli temp będącej częścią pojedynczej partii. Czy możesz wypróbować poniższy skrypt?

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
źródło
1
Nutowy; tempdb..w powyższym kodzie jest bardzo ważne. Musi poprzedzać nazwę tabeli tymczasowej. Samo sprawdzenie OBJECT_ID('#Results')to za mało. Tabele tymczasowe są przechowywane w bazie danych TempDB. Per Microsoft: Systemowa baza danych TempDB to globalny zasób, który jest dostępny dla wszystkich użytkowników podłączonych do instancji SQL Server lub połączonych z bazą danych SQL
iCode
Dzięki, @iCode. To jest klucz do upuszczenia tabel tymczasowych: trzeba to zrobić, tempdbinaczej nie zniknie.
Alex
37

Można to osiągnąć za pomocą jednego wiersza kodu:

IF OBJECT_ID('tempdb..#tempTableName') IS NOT NULL DROP TABLE #tempTableName;   
S Kryszna
źródło
1
muszę patrzeć na to codziennie
Ab Bennett
28

To zadziałało dla mnie: 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;
użytkownik219628
źródło
1
To jest po prostu inna składnia dla upuszczenia tabeli warunkowej. To interesujące, ale nie rozwiązuje pytania OP, a większość z nich jest zbędna. Jeśli po prostu sprawdzisz, czy OBJECT_ID (N'tempdb .. # Results ') nie ma wartości NULL, wystarczy, aby udowodnić, że obiekt już istnieje.
Davos,
21

Tylko mały komentarz z mojej strony, ponieważ OBJECT_IDto nie działa dla mnie. Zawsze to zwraca

`#tempTable nie istnieje

..even choć nie istnieje. Właśnie znalazłem, że jest przechowywany pod inną nazwą (po _podkreśleniu):

#tempTable________

Działa to dla mnie dobrze:

IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#tempTable%') BEGIN
   DROP TABLE #tempTable;
END;
Ivan Sivak
źródło
6
Uwaga: ten kod wykryje tabelę, jeśli została utworzona przez dowolny wątek. Tabele temp. Pojedynczych # są tworzone osobno dla każdego wątku / obiektu wywołującego do przechowywanego proc, dlatego podkreśla nazwę, aby istniała inna kopia dla wątku / procesu. Identyfikator_obiektu powinien działać poprawnie dla bieżącego wątku, o ile korzystasz z SQL 2005 lub nowszej wersji.
Bytemaster
12

Teraz możesz użyć poniższej składni, jeśli korzystasz z jednej z nowych wersji programu SQL Server (2016+).

DROP TABLE IF EXISTS schema.yourtable(even temporary tables #...)
Othman Dahbi-Skali
źródło
1
Używam SSMS 17.3, a to dajeIncorrect syntax near the keyword 'IF'.
StingyJack
7
@StingyJack Ponieważ składnia SQL nie jest związana z wersją SSMS, ale z wersją SQL Server. IF [NOT] EXISTSKlauzula jest dostępna z SQL Server 2016. To nie ma znaczenia, który SSMS wersji używasz.
Pred
10

pmac72 używa GO, aby podzielić zapytanie na partie i używa ALTER.

Wygląda na to, że uruchamiasz tę samą partię, ale uruchamiasz ją dwukrotnie po zmianie: DROP ... CREATE ... edit ... DROP ... CREATE ..

Być może opublikuj swój dokładny kod, abyśmy mogli zobaczyć, co się dzieje.

gbn
źródło
7

Zazwyczaj trafiam ten błąd, gdy już utworzyłem tabelę tymczasową; kod, który sprawdza, czy w instrukcji SQL nie ma błędów, widzi „starą” tabelę tymczasową na miejscu i zwraca błędne obliczenie liczby kolumn w późniejszych instrukcjach, tak jakby tabela tymczasowa nigdy nie została usunięta.

Po zmianie liczby kolumn w tabeli tymczasowej po utworzeniu wersji z mniejszą liczbą kolumn, upuść tabelę i NASTĘPNIE uruchom zapytanie.

Jacob Griffin
źródło
6

Niedawno widziałem, jak DBA robi coś podobnego do tego:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)
anonxen
źródło
2
Ta instrukcja try przechwytuje inne błędy, które mogą wystąpić podczas próby upuszczenia tabeli. Ten kod zakłada, że ​​jedynym powodem niepowodzenia próby jest to, że tabela nie istnieje. Prawdopodobnie działałoby to przez większość czasu, ale nie gwarantowałbym tego. Jeśli instrukcja try nie powiedzie się z innego powodu, pojawi się błąd podczas tworzenia tabeli, ponieważ zamaskowało to prawdziwy problem z upuszczeniem tabeli.
Davos,
To działa, ale źle. Nie zachęcam do tego, gdy jest sprytne i idealne rozwiązanie. A także, mimo że wersja OP określona w 2005 roku, spróbuj złapać blok w starszych wersjach
dejjub-AIS
Innym problemem jest ideologia użycia try / catch vs. logiki. Więcej debaty można zobaczyć tutaj: stackoverflow.com/questions/17335217/try-catch-or-if-statement/…
logikolog
3

Mój kod używa Sourcetabeli, która się zmienia, i Destinationtabeli, która musi pasować do tych zmian.

-- 
-- 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
źródło
1

Tak, „nieprawidłowa kolumna” ten błąd podniesiony z wiersza „wybierz firmę, stepid, fieldid, NewColumn z #Results”.

Istnieją dwie fazy uruchamiania t-sql,

po pierwsze, parsowanie, w tej fazie serwer sql sprawdza poprawność przesłanego ciągu sql, w tym kolumny tabeli, i optymalizuje zapytanie, aby uzyskać najszybsze przywracanie.

po drugie, uruchamianie, przywracanie danych.

Jeśli tabela #Results istnieje, wówczas proces analizowania sprawdzi, czy określone kolumny są poprawne, czy nie, w przeciwnym razie (tabela nie istnieje) analizowanie zostanie przekazane zgodnie z podanymi kolumnami sprawdzającymi.

pnbps
źródło
0

Po zmianie kolumny w tabeli tymczasowej należy usunąć tabelę przed ponownym uruchomieniem zapytania. (Tak, to denerwujące. Właśnie to musisz zrobić.)

Zawsze zakładałem, że dzieje się tak, ponieważ sprawdzanie „niepoprawnej kolumny” jest wykonywane przez analizator składni przed uruchomieniem zapytania, więc jest ono oparte na kolumnach w tabeli przed usunięciem ..... i to również powiedział pnbs.

Woric
źródło