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


663

Я использую следующий код, чтобы проверить, существует ли временная таблица и удалить таблицу, если она существует, прежде чем создавать снова. Работает нормально, пока я не меняю столбцы. Если я добавлю столбец позже, он выдаст ошибку «неверный столбец». Пожалуйста, дайте мне знать, что я делаю неправильно.

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. Если вы скопируете приведенный выше код и запустите его в первый раз, вы не получите никакой ошибки. Теперь, если вы добавите столбец во временную таблицу и добавите столбец в оператор выбора, он скажет, что столбец не найден (или что-то в этом роде).
Шридхар

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

1
Похоже, вам просто нужны GO заявления.
Сэм Йи

Ответы:


734

Я не могу воспроизвести ошибку.

Возможно, я не понимаю проблемы.

Следующее прекрасно работает для меня в 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 (Company CHAR (3), StepId INT) выберите компанию, stepid из #results теперь возвращается к оператору создания и добавляет столбец fieldid в end.change операторе select, чтобы включить fieldid и запустить его.
Шридхар

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

77
@ Conrad.Dean двойная точка - это сокращение от .dbo.
deutschZuid

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

8
Ваш код настолько отличается от OP, что ваше утверждение «невозможно воспроизвести» не имеет смысла. Я рад за тебя, что ты заставил его работать по-другому.
Джерард ONeill

85

Заявление должно быть порядка

  1. Изменить заявление для таблицы
  2. ИДТИ
  3. Выберите заявление.

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

С 'GO', он будет рассматривать часть скрипта до 'GO' как один пакет и будет выполняться перед тем, как войти в запрос после 'GO'.


7
Это должно быть помечено как правильный ответ. Дело не в том, что на самом деле SELECT собирается запускаться до создания таблицы, а в том, что он анализируется и выдает ошибку перед запуском, потому что существует существующая таблица с именем #Results, в которой еще нет столбца FieldId в время синтаксического анализа. Добавление туда GO разделяет запрос на пакеты, которые анализируются и запускаются отдельно.
Давос,

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затем используете приведенный ниже синтаксис, чтобы удалить временную таблицу и воссоздать ее. Больше информации здесь MSDN

Синтаксис

DROP TABLE [ЕСЛИ СУЩЕСТВУЕТ] [database_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 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 .. # Results ') не равен нулю, этого достаточно, чтобы доказать, что объект уже существует.
Давос,

21

Просто небольшой комментарий с моей стороны, так как OBJECT_IDу меня не работает. Это всегда возвращает это

`#tempTable не существует

..even хотя это делает существует. Я только что обнаружил, что он хранится под другим именем (с _подчеркиванием), например:

#tempTable________

Это хорошо работает для меня:

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

6
Внимание: этот код обнаружит таблицу, если она была создана каким-либо потоком. Одиночные # временные таблицы создаются отдельно для каждого потока / вызывающей стороны для хранимого процесса, поэтому в имени подчеркивается то, что для каждого потока / процесса существует другая копия. 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.

Вы, кажется, запускаете тот же пакет, но запускаете его дважды после изменения: DROP ... CREATE ... edit ... DROP ... CREATE ..

Возможно, опубликуйте свой точный код, чтобы мы могли видеть, что происходит.


7

Я обычно сталкиваюсь с этой ошибкой, когда я уже создал временную таблицу; код, который проверяет оператор SQL на наличие ошибок, видит «старую» временную таблицу на месте и возвращает неверный счетчик числа столбцов в последующих операторах, как если бы временная таблица никогда не удалялась.

После изменения количества столбцов во временной таблице после создания версии с меньшим количеством столбцов удалите таблицу и, затем, выполните свой запрос.


6

Я недавно видел, как администратор баз данных делал что-то похожее на это:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)

2
Этот оператор try перехватывает другие ошибки, которые могут возникнуть при попытке удалить таблицу. Этот код предполагает, что единственная причина, по которой попытка не удалась, заключается в том, что таблица не существует. Это, вероятно, будет работать большую часть времени, но я не гарантирую это. Если оператор try не работает по какой-либо другой причине, вы получите ошибку при создании таблицы, потому что это скрыло реальную проблему с удалением таблицы.
Давос,

Это работает, но плохо, я не поощряю трудный путь, когда есть умное и идеальное решение. А также, хотя OP указала версию 2005 года, try catch catch не поддерживается в более старых версиях
dejjub-AIS

Другая проблема заключается в идеологии использования try / catch против логики. Вы можете увидеть больше дебатов здесь: stackoverflow.com/questions/17335217/try-catch-or-if-statement/…
логиксолог

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 from #Results».

Есть две фазы запуска t-sql,

во-первых, на этом этапе сервер sql проверяет исправление введенной вами строки sql, включая столбец таблицы, и оптимизирует ваш запрос для максимально быстрого получения.

во-вторых, бег, извлечение данных.

Если таблица #Results существует, то процесс синтаксического анализа проверит, что указанные вами столбцы действительны или нет, иначе (таблица не существует) синтаксический анализ будет выполнен путем пропуска проверочных столбцов, как вы указали.


0

Когда вы изменяете столбец во временной таблице, вы должны удалить таблицу перед повторным запуском запроса. (Да, это раздражает. Просто то, что вы должны сделать.)

Я всегда предполагал, что это потому, что проверка «недопустимого столбца» выполняется парсером до запуска запроса, поэтому он основан на столбцах таблицы, прежде чем он будет отброшен ..... и это то, что также сказал pnbs.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.