SELECT INTO резервирует имя #Object в TempDB до времени выполнения?

8

Собрав воедино быстрый процесс для отладки, я столкнулся с ошибкой в ​​компиляторе.

create proc spFoo
    @param bit
as
begin
    if @param = 0
    begin 
        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

Попытка вышеупомянутого возвращает следующую ошибку

Сообщение 2714, уровень 16, состояние 1, процедура spFoo, строка 19
В базе данных уже есть объект с именем #bar.

В понятном для человека смысле, процесс, кажется, в порядке: только один select intoоператор когда-либо будет выполнен, так как они заключены в if-elseблоки. Впрочем, SQL-сервер не может подтвердить, что операторы логически исключены друг из друга. Возможно, еще более запутанным является то, что ошибка остается, когда drop table #fooона помещается в блок if-else (который, как предполагается, сообщит компилятору об освобождении имени объекта), как показано ниже.

create proc spFoo
    @param bit
as
begin
    select top 1 * 
    into #bar
    from [master].dbo.spt_values

    if @param = 0
    begin 
        drop table #bar;

        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        drop table #bar;

        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

Сам процесс в порядке. Я смирился с этим и написал операторы create table #foo( ... )and insert #foo ( ... ), я пытался пропустить select * into синтаксис. На данный момент я просто пытаюсь понять, почему компилятор помешался на мне с синтаксисом lazy-guy. Единственное, о чем я могу думать, это то, что команда DDL резервирует имя объекта IN TEMPDB .

Почему жирный текст?

create proc spIck
as
begin
    create table #ack ( col1 int );
    drop table #ack;
    create table #ack ( colA char( 1 ) );
    drop table #ack;
end;

Это происходит с тем же кодом ошибки, что и выше. Но следующее ...

create proc spIck
as
begin
    create table ack ( col1 int );
    drop table ack;
    create table ack ( colA char( 1 ) );
    drop table ack;
end;

... успешно. То же самое следует выше к первоначальной попытке процедуры. Так...

Мой вопрос это

В чем разница (и почему она присутствует) в резервировании имен TempDBобъектов для объектов в отличие от пользовательских баз данных. Ни одна из ссылок на логическую обработку запросов или ссылок на команды DDL, которые я рассмотрел, не объясняет этого.

Питер Вандивье
источник
1
Этот снимок экрана из «Руководства гуру по хранимым процедурам, XML и HTML на SQL Server» (в Google Книгах) кажется уместным и показывает, что он работает с 7.0 i.stack.imgur.com/8pDGT.png
Martin Smith
Похоже, что это страница 6 (к вашему сведению для всех, кто придет в ветку позже).
Питер Вандивье

Ответы:

6

Это не имеет ничего общего с резервированием имени объекта в TempDB или чем-либо, связанным с временем выполнения. Это просто синтаксический анализатор, неспособный следовать логике или путям кода, который гарантирует, что ваш код не может попытаться создать эту таблицу дважды. Обратите внимание, что вы получите точно такую ​​же ошибку (не во время выполнения!), Если просто нажать кнопку Parse ( Ctrl+ F5). В основном, если у вас есть это:

IF 1=1 
  CREATE TABLE #foo(id1 INT);
ELSE
  CREATE TABLE #foo(id2 INT);

Парсер видит это:

  CREATE TABLE #foo(id1 INT);
  CREATE TABLE #foo(id2 INT);

Почему это не работает таким образом для реальных таблиц, включая реальные пользовательские таблицы, созданные в TempDB (обратите внимание, что это также не зависит от базы данных)? Единственный ответ, который я могу предложить, состоит в том, что синтаксический анализатор имеет другой набор правил для таблиц #temp (также есть много других отличий). Если вам нужны более конкретные причины, вам нужно открыть дело в Microsoft и посмотреть, предоставят ли они вам дополнительную информацию. Я думаю, вам скажут: «Вот как это работает».

Еще немного информации в этих ответах:

Аарон Бертран
источник
На самом деле, « так оно и работает » - это именно тот ответ, который у них есть. Ну да ладно ...
Питер Вандивьер