Mettre en place un proc quickie pour aider au débogage, j'ai rencontré ce qui semble être une erreur dans le compilateur.
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;
La tentative ci-dessus renvoie l'erreur suivante
Msg 2714, niveau 16, état 1, procédure spFoo, ligne 19
Il existe déjà un objet nommé '#bar' dans la base de données.
Dans un sens lisible par l'homme, le proc semble être bien: une seule select into
instruction sera jamais exécutée car elles sont enveloppées à l'intérieur des if-else
blocs. Très bien cependant, SQL Server ne peut pas confirmer que les instructions sont logiquement exclues les unes des autres. Le plus déroutant est peut-être que l'erreur persiste lorsque le drop table #foo
est placé à l'intérieur du bloc if-else (dont on suppose qu'il dirait au compilateur de désallouer le nom de l'objet) comme ci-dessous.
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;
Le proc lui-même est très bien. Je l'ai aspiré et j'ai écrit les déclarations create table #foo( ... )
et insert #foo ( ... )
, j'avais essayé de sauter avec la select * into
syntaxe. À ce stade, j'essaie simplement de comprendre pourquoi le compilateur m'a chié avec la syntaxe paresseuse. La seule chose à laquelle je peux penser est que la commande DDL réserve le nom de l'objet IN TEMPDB .
Pourquoi le texte en gras?
create proc spIck
as
begin
create table #ack ( col1 int );
drop table #ack;
create table #ack ( colA char( 1 ) );
drop table #ack;
end;
Cela échoue avec le même code d'erreur que ci-dessus. Mais ce qui suit ...
create proc spIck
as
begin
create table ack ( col1 int );
drop table ack;
create table ack ( colA char( 1 ) );
drop table ack;
end;
... réussit. La même chose ci-dessus s'applique à la tentative de proc d'origine. Donc...
Ma question est la suivante
Quelle est la différence (et pourquoi est-elle présente) dans la réservation de nom d' TempDB
objet par opposition aux bases de données utilisateur. Aucune des références Logical Query Processing ni des références de commande DDL que j'ai examinées ne semble expliquer cela.
la source
Réponses:
Cela n'a rien à voir avec les réservations de nom d'objet dans TempDB ou à voir avec l'exécution. Il s'agit simplement de l'analyseur incapable de suivre la logique ou les chemins de code qui garantissent que votre code ne pourrait pas essayer de créer deux fois cette table. Notez que vous obtenez exactement la même erreur (hors exécution!) Si vous cliquez simplement sur le bouton Analyser ( Ctrl+ F5). Fondamentalement, si vous avez ceci:
L'analyseur voit ceci:
Pourquoi cela ne fonctionne-t-il pas de cette façon pour les tables réelles , y compris les tables utilisateur réelles créées dans TempDB (notez que ce n'est pas spécifique à la base de données non plus)? La seule réponse que je peux suggérer est que l'analyseur a un ensemble de règles différent pour les tables #temp (il y a aussi beaucoup d'autres différences). Si vous voulez des raisons plus spécifiques, vous devrez ouvrir un dossier avec Microsoft et voir si elles vous donneront plus de détails. Je suppose que l'on vous dira: "c'est ainsi que cela fonctionne".
Quelques informations supplémentaires dans ces réponses:
la source