Вставка SQL во временную таблицу в блоках If и Else

Я пытаюсь заполнить временную таблицу на основе результата условия в SQL 2005. Временная таблица будет иметь одинаковую структуру в любом случае, но будет заполняться с использованием другого запроса в зависимости от условия. Приведенный ниже упрощенный пример скрипта не проходит проверку синтаксиса блока ELSE INSERT INTO с ошибкой:

В базе данных уже есть объект с именем #MyTestTable.

DECLARE @Id int
SET @Id = 1

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

IF (@Id = 2) BEGIN 
    SELECT 'ABC' AS Letters
    INTO #MyTestTable;
END ELSE BEGIN
    SELECT 'XYZ' AS Letters
    INTO #MyTestTable;
END

Я мог бы создать временную таблицу перед оператором IF/ELSE, а затем просто выполнить операторы INSERT SELECT в условных блоках, но в таблице будет много столбцов, и я пытался быть эффективным в этом. Это единственный вариант? Или есть способ заставить это работать?

Спасибо, Мэтт


person CuppM    schedule 11.11.2010    source источник


Ответы (9)


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

DECLARE @Command  varchar(500)

DECLARE @Id int 
SET @Id = 2

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

IF (@Id = 2) BEGIN  
    SET @Command = 'SELECT ''ABC'' AS Letters INTO #MyTestTable'
END ELSE BEGIN 
    SET @Command = 'SELECT ''XYZ'' AS Letters INTO #MyTestTable'
END 

EXECUTE (@Command)

select * from #MyTestTable

но временная таблица существует только до тех пор, пока динамическая сессия. Так что, увы, похоже, вам придется сначала объявить таблицу, а затем заполнить ее. Неудобный код для написания и поддержки, возможно, но он будет работать достаточно эффективно.

person Philip Kelley    schedule 11.11.2010
comment
В моем ответе не говорится и не рекомендуется использование динамического SQL - фактически он демонстрирует, что динамический SQL не может использоваться для решения проблемы, и делает вывод, что конкретное объявление временной таблицы перед вставкой данных, вероятно, путь. - person Philip Kelley; 04.06.2014
comment
Вы можете использовать динамический SQL и вставить его в глобальную временную таблицу (##MyTesttable), а затем удалить глобальную таблицу. Добавлю как отдельный ответ - person Rym; 26.07.2017

Отвечаю с опозданием на 8 лет, но я удивлен, что никто не подумал:

select * into #MyTempTable from...
where 1=2

IF -- CONDITION HERE
insert into #MyTempTable select...
ELSE
insert into #MyTempTable select...

Просто, быстро и работает. Не требуется динамический sql

person Gaspa79    schedule 15.02.2018
comment
Великолепно! Спустя годы это все еще фантастика для тех из нас, кто ищет помощи. - person MsTapp; 26.12.2019
comment
Действительно хорошее решение, но хотелось бы добавить, что «Выбрать 0 лучших *» было бы лучше, чем навязывать условие. Кроме того, если исходная таблица содержит столбец идентификаторов, его необходимо отключить перед вставкой. - person Sushant Sardeshpande; 13.04.2020
comment
Где 1 = 2 работает точно так же, как и top 0 (и это также работает в mysql), поэтому объективно это не лучше, чем наложение условия. Вы правы насчет столбца ID. - person Gaspa79; 30.06.2020

В сценарии, который вы предоставляете, вы можете сделать это

DECLARE @Id int
SET @Id = 1

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

SELECT 
  CASE WHEN (@Id = 2) 
    THEN 'ABC' 
    ELSE 'XYZ' 
  END AS Letters
INTO #MyTestTable;

Но в противном случае вам нужно будет создать таблицу перед if statement, как это

Create Table #MyTestTable (
  MyValue varchar(3)
)
IF (@Id = 2) BEGIN 
  Insert Into (MyValue)
  SELECT 'ABC' AS Letters;
END ELSE BEGIN
  Insert Into (MyValue)
  SELECT 'XYZ' AS Letters;
END
person John Hartsock    schedule 11.11.2010
comment
Да, для этого сценария это сработает. Но реальные запросы намного сложнее. - person CuppM; 11.11.2010

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

IF 1 = 1 -- Replace with actual condition
BEGIN
    SELECT * INTO #tmp1 FROM dbo.Table1
END
ELSE
BEGIN
    SELECT * INTO #tmp2 FROM dbo.Table2
END

-- Inserting data into global temp table so sql server can't complain on not recognizing in a context
DECLARE @Command VARCHAR(MAX)
IF OBJECT_ID('tempdb..#tmp1') IS NOT NULL
BEGIN
    SET @Command = 'SELECT * INTO ##tmp FROM #tmp1'
END
ELSE
BEGIN
    SET @Command = 'SELECT * INTO ##tmp FROM #tmp2'
END

EXECUTE(@Command)
SELECT * INTO #tmpFinal FROM ##tmp -- Again passing data back to local temp table from global temp table to avoid seeing red mark

IF OBJECT_ID('tempdb..##tmp') IS NOT NULL DROP TABLE ##tmp
IF OBJECT_ID('tempdb..#tmp1') IS NOT NULL DROP TABLE #tmp1
IF OBJECT_ID('tempdb..#tmp2') IS NOT NULL DROP TABLE #tmp2

SELECT * FROM #tmpFinal

IF OBJECT_ID('tempdb..#tmpFinal') IS NOT NULL DROP TABLE #tmpFinal
person Prateek Rai    schedule 28.12.2018

Это старая проблема, но для всех, кто приходит сюда:

Динамический ответ SQL, данный пользователем Philip Kelley, не работает для локальных временных таблиц (#Mytemp). Что вы можете сделать, так это создать динамический SQL, чтобы вставить его в глобальную временную таблицу (##MyTemp), которую позже можно удалить.

DECLARE @Command  varchar(500)

DECLARE @Id int 
SET @Id = 2

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

IF (@Id = 2) BEGIN  
    SET @Command = 'SELECT ''ABC'' AS Letters INTO ##MyTestTable'
END ELSE BEGIN 
    SET @Command = 'SELECT ''XYZ'' AS Letters INTO ##MyTestTable'
END 

EXECUTE (@Command)

select * from ##MyTestTable

DROP ##MyTestTable
person Rym    schedule 26.07.2017

этот код может помочь вам

--creating temptable using columns of two existing tables
--you can create your temp table Using other methods

select top 0 VI.*,VU.FullName
into #mytemptable
from dbo.Items VI inner join
     dbo.Users as VU 
     on VU.Id=VI.Id

--insert your data base on your condition
if(i<2) --First Condition
begin
INSERT INTO #mytemptable
SELECT VI.*,VU.FullName 
from dbo.Items VI inner join
     dbo.Users as VU 
     on VU.Id=VI.Id
end
Else if(2<i) --Second Condition
begin
INSERT INTO #mytemptable
SELECT VI.*,VU.FullName 
from dbo.Items VI inner join
     dbo.Users as VU 
     on VU.Id=VI.Id
end

select * from #mytemptable --show result

drop table #mytemptable --drop table if its needed

этот код работает в sql server 2014, я не знаю, работает ли он в sql 2005 или нет

person Mohaddes Sokhangou    schedule 08.01.2018

Я пробовал это:

SELECT S1.* INTO #MytestTable
FROM 
(   SELECT 'ABC' AS Letters WHERE 1 = CASE @Id=2 THEN 1 ELSE 2 END
    UNION
    SELECT 'XYZ' AS Letters WHERE 1 = CASE @Id=1 THEN 1 ELSE 2 END
) AS S1

Это решение лучше, если позже вам нужно будет добавить столбцы в #MyTestTable, потому что в противном случае вы должны физически удалить его, прежде чем повторно запускать свой скрипт, что раздражает в условиях тестирования.

person Cyrage    schedule 26.04.2019

Вы можете попробовать этот код.

IF (CONDITION HERE)
       begin
           select * into #MyTempTable from tablename ....
       end
       ELSE
           truncate table #MyTempTable 
           insert into #MyTempTable 
           select * from tablename ....
       end

Спасибо!!!

person Nitika Chopra    schedule 18.03.2021

Вы можете удалить таблицу перед SELECT INTO в обоих случаях, например:

DECLARE @Id int 
SET @Id = 1  

IF (@Id = 2) BEGIN  
    IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable
    SELECT 'ABC' AS Letters 
    INTO #MyTestTable; 
END ELSE BEGIN 
    IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable 
    SELECT 'XYZ' AS Letters 
    INTO #MyTestTable; 
END 

Обновление после комментария:

Это раздражает.

Как насчет двух отдельных временных таблиц? Затем после входа в систему If/Else проверьте наличие каждого из них и, если он существует, выберите третью временную таблицу? Это может быть не очень хорошо, но важно это или нет, зависит от того, для чего вам это нужно.

person Phil Sandler    schedule 11.11.2010
comment
Я пробовал это. Я поставил IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable в каждом блоке перед INSERT INTO, но в результате получил то же самое. - person CuppM; 11.11.2010
comment
Был не я. Но, может быть, это потому, что ваше предложение тоже не проходит проверку синтаксиса? Я думаю, что две отдельные временные таблицы начинают выполнять больше работы, чем просто создание временной таблицы перед IF/ELSE. - person CuppM; 11.11.2010
comment
Да, создание временной таблицы перед логикой кажется лучшим вариантом, но, не зная больше о том, что вы делаете, трудно сказать определенно. - person Phil Sandler; 11.11.2010