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


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.