Перевірте, чи існує тимчасова таблиця, і видаліть, якщо вона існує, перш ніж створити тимчасову таблицю


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

Де ви додаєте стовпець? чи можете ви опублікувати точний код, який дає вам помилку?
Макроси

Я додаю стовпець до таблиці # Результати. Якщо ви скопіюєте вищевказаний код і запустите його вперше, ви не отримаєте помилок. Тепер, якщо ви додаєте стовпець до таблиці темп і додаєте стовпчик до вибору оператора, він скаже, що стовпець не знайдено (або щось подібне).
Шрідхар

22
Розглянемо з допомогою наступною схемою: BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT. Якщо транзакція пройде успішно, таблиця буде видалена. Якщо вона не вдасться, таблиця також буде відсутня (оскільки вона створена в рамках транзакції). У будь-якому випадку: Не потрібно перевіряти, чи таблиця вже існує.
Хайнзі

1
Схоже, що вам просто потрібні заяви GO.
сам

Відповіді:


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 .. # Результати') НЕ НУЛЬНИЙ ТАБЛИКА ДРОПУВАННЯ # Результати `Створіть таблицю # Результати (компанія CHAR (3), StepId INT) виберіть компанію; стовпчик fieldid у end.change select оператор, щоб включити fieldid та запустити його.
Шрідхар

28
'tempdb..#name'саме те, що мені було потрібно. Я використовував 'dbo.#name', як дурень. Я отримую tempdbчастину, але що з подвійними крапками?
Conrad.Dean

77
@ Conrad.Dean double dot - це абревіатура для .dbo.
deutschZuid

32
@deutschZuid точніше сказати, що подвійна крапка - це схема за замовчуванням користувача, яка, як правило, є dbo (що не є ідеальною ідеєю, зробити dbo схемою за замовчуванням для користувачів, але зазвичай так йде)
jcollum

8
Ваш код настільки відрізняється від OP, що ваше твердження "не може відтворити" безглуздо. Я радий за те, що ти змусив це працювати по-іншому.
Джерард ONeill

85

Заява має бути наказом

  1. Змінити заяву для таблиці
  2. ПОВЕРНУТИСЯ
  3. Виберіть заяву.

Без 'GO' між ними, вся справа буде розглядатися як один єдиний сценарій, і коли оператор select шукає стовпець, він не буде знайдений.

З «GO» він буде розглядати частину сценарію до «GO» як одну єдину партію і виконуватиметься перед тим, як потрапити в запит після «GO».


7
Це слід позначити як правильну відповідь. Справа не в тому, що SELECT насправді буде запускатися перед таблицею створення, це те, що вона розбирається і видає помилку перед запуском, тому що існує існуюча таблиця під назвою #Results, яка ще не має стовпця FieldId у час розбору оператора select. Додавання GO туди розділяє запит на партії, які аналізуються та виконуються окремо.
Давос

2
Я не можу повірити в невідповідність голосів між цим та найвищою відповіддю, що настільки змінило кодекс - не пояснюючи чому - що воно було безглуздим як відповідь.
підкреслюй_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потім використовуєте наведений нижче синтаксис, щоб скинути таблицю темп і відтворити її. Більше інформації тут MSDN

Синтаксис

СКЛАД ТАБЛИЦІ [ЯКЩО ВИНАЄТЬСЯ] [ім’я_бази. [схема_назви]. | схема_назви. ] 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 Existsдля SQL 2016 чи Azure? Синтаксис доступний починаючи з SQL 2008. Бачите посилання MSDN у своїй відповіді? Коефіцієнт продуктивності?
HappyTown

4
Не звертай уваги. Тепер я зрозумів, що DROP TABLEпідтримується SQL Server 2008, але IF EXISTSпункт був введений у 2016 році.
HappyTown

1
Я використовую INTO: виберіть * 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..у наведеному вище коді дуже важливо. Це повинно передувати назвою таблиці темп. Проста перевірка OBJECT_ID('#Results')недостатня. Тимчасові таблиці зберігаються в базі даних TempDB. На Microsoft: системна база даних TempDB - це глобальний ресурс, який доступний для всіх користувачів, підключених до екземпляра SQL Server або підключених до бази даних SQL
iCode

Дякую, @iCode. Це ключ до відкидання тимчасових таблиць: це потрібно зробити, tempdbабо він не пропаде.
Олексій

37

Це може бути здійснено за допомогою одного рядка коду:

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

1
я повинен дивитись на це кожен день
Аб Беннетт

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
Це просто інший синтаксис для краплі умовної таблиці. Це цікаво, але не вирішує питання ОП, і більшість із них є зайвим. Якщо ви просто перевірите, що OBJECT_ID (N'tempdb .. # Результати ') не є нульовим, то цього достатньо, щоб довести, що об'єкт вже існує.
Давос

21

Просто невеликий коментар з моєї сторони, оскільки OBJECT_IDце не працює для мене. Це завжди це повертає

`#tempTable не існує

..even хоча це робить існує. Щойно я виявив, що він зберігається з іншим іменем (з поштовим шрифтом _підкресленнями):

#tempTable________

Це добре для мене:

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

6
Застереження: Цей код виявить таблицю, якщо вона була створена будь-яким потоком. Одиночні таблиці # temp створюються окремо для потоку / абонента, що зберігається, тому підкреслюється в імені так, що для потоку / процесу існує інша копія. 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 ви використовуєте.
Перед

10

pmac72 використовує GO для розбиття запиту на партії та використання ALTER.

Ви, здається, виконуєте одну і ту ж партію, але запускаєте її двічі після її зміни: ЗРОБИТИ ... СТВОРИТИ ... редагувати ... ЗРОБИТИ ... СТВОРИТИ ..

Можливо, опублікуйте свій точний код, щоб ми могли побачити, що відбувається.


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
Ця операція спробу дозволить знайти інші помилки, які можуть виникнути при спробі скинути таблицю. Цей код передбачає, що єдиною причиною спроби не вдалося, тому що таблиця не існує. Це, мабуть, спрацює більшу частину часу, але я не гарантую це. Якщо оператор спробу виходить з ладу з якоїсь іншої причини, ви отримаєте помилку під час створення таблиці, оскільки це замаскувало справжню проблему з випаданням таблиці.
Давос

Це працює, але погано, я не заохочую важкий шлях, коли є розумне і ідеальне рішення. А також, хоча версія, визначена ОР 2005 року, спробу блокування лову не підтримується у старих версіях
dejjub-AIS

Інша проблема з цим - це ідеологія використання логіки try / catch vs. Ви можете бачити більше дискусій тут: 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 також сказав.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.