7
votes

Création de tables TEMP en double à l'intérieur des procédures stockées imbriquées

Voici la situation:

Procédure 1 crée une table Temp (#MyTable) et appelle Procédure 2. Procédure 2 essaie également de créer #MyTable, avec des colonnes différentes. Lorsque la procédure 2 essaie d'insérer des données dans #MyTable, une erreur se passe-t-elle plainte "Nom de colonne non valide". J'ai deux questions à ce sujet: p>

1) ne devrait-il pas que le système ne se plaignait pas lorsque #MyTable est créé à l'intérieur de la procédure 2? Je comprends pourquoi il ne peut pas s'opposer au temps de compilation, mais à l'exécution, je m'attendrais à une erreur. P>

2) Étant donné qu'il ne se plaignait pas de la création et de choisir parmi #MyTable À l'intérieur de la procédure 2, vous voyez la nouvelle colonne, pourquoi se plaint-elle de l'insert? p>

ci-dessous est le code. Entraînant que l'une ou l'autre instruction insertion obtiendra l'erreur. P>

(Je sais beaucoup de façons de résoudre cette situation, donc je n'ai pas besoin de réponses à ce sujet. Je veux juste comprendre ce qui se passe.) P >

IF OBJECT_ID(N'dbo.MYPROC1', N'P') IS NOT NULL
    DROP PROCEDURE dbo.MYPROC1;
GO

CREATE PROCEDURE dbo.MYPROC1
AS
    CREATE TABLE dbo.#MYTABLE ( Name VARCHAR(256) );

    SELECT
        'DO NOTHING 1' AS TABLENAME;

    EXEC dbo.MYPROC2;

GO

IF OBJECT_ID(N'dbo.MYPROC2', N'P') IS NOT NULL
    DROP PROCEDURE dbo.MYPROC2;
GO

CREATE PROCEDURE dbo.MYPROC2
AS
    SELECT
        'INSIDE PROC 2 BEFOREHAND' AS TABLENAME
       ,*
    FROM
        dbo.#MYTABLE;

    CREATE TABLE dbo.#MYTABLE
        (
         Name VARCHAR(256)
        ,LastName VARCHAR(256)
        );

    --INSERT  INTO dbo.#MYTABLE
    --        ( Name, LastName )
    --        SELECT
    --            'BARACK'
    --           ,'OBAMA';

    SELECT
        'INSIDE PROC 2 AFTERWARDS' AS TABLENAME
       ,*
    FROM
        dbo.#MYTABLE;

    --INSERT  INTO dbo.#MYTABLE
    --        ( Name, LastName )
    --        SELECT
    --            'BARACK'
    --           ,'OBAMA';

    SELECT
        'DO NOTHING 2' AS TABLENAME;

GO

EXEC MYPROC1;


0 commentaires

4 Réponses :


-1
votes

Eh bien, à la première vue, votre hypothèse est correcte, mais seulement au premier.

Lorsque vous créez une table temporaire nommée MyTable, SQL Server crée une table réelle dans TEMPDB, qui est nommé quelque chose comme «Mytable _____________...._____ 01d ', donc lorsque tout autre morceau de code crée une table avec le même nom mais dans les différents Portée, le serveur peut faire la différence d'entre eux.

Et dans votre cas, vous créez des tables temporaires locales dans deux scopes différentes - deux procédures différentes, jamais l'esprit que l'on l'appelle une autre, vous ne pouvez pas accéder à la table créée dans la deuxième procédure à partir du premier.

Ce que je vais vous suggérer, c'est de sélectionner des données à SYS.Objects, de sorte que vous puissiez voir qu'il existe deux tableaux réels et différents créés - Sélectionnez le nom de templdb..sysobjects où nom comme "MyTable%"

Et dernier - vous utilisez le même nom et attendez-vous à accéder à la table "la plus petite" de la scorie, mais réellement serveur utilise la table créée en premier. Supposons que SQL Server sélectionne simplement le top 1 de Sys.Objects où la portée et le nom correspondent à ceux actuels.


7 commentaires

Cette réponse explique la question n ° 1 très bien, merci. Mais je ne comprends toujours pas pourquoi l'insertion et la sélection se comportent différemment. Pourquoi choisir "voir" la table plus récente et insérer "voir" l'aîné?


Eh bien, c'est une bonne question, je ne peux pas y répondre (je suis désolé, je ne l'ai pas lu complètement lorsque je répondais à votre message). Il devrait probablement être dirigé vers une équipe plus compétente, ceux qui sont en contact de la manière dont les choses à l'intérieur du serveur SQL fonctionnent. Je vais essayer de gérer le même exemple sur différentes versions de SQL Server et voir comment il se comporte. Quelle version utilisez-vous?


"Vous ne pouvez pas accéder à la table créée en deuxième procédure à partir du premier." Ceci est une erreur. Les tables TEMP ont une sorte de portée dynamique. Ils ne sont pas scopés comme une variable. Une fois la table créée, d'autres procédures peuvent y lire et l'écrire. Bien que les lectures soient apparemment ombrées.


@ShannonaSverance, eh bien si vous accédez à la table directement par son nom à Tampdb, alors - oui. Sinon, vous ne pouvez pas choisir parmi la table Temp locale créée en sous-étendue (dans cette affaire de procédure stockée appelée à une autre procédure stockée) de la portée des parents.


Un parent ne peut accéder à la table Temp locale d'un enfant, car la table est détruite à la sortie de la procédure d'enfant. Mais il s'agit d'un cas de l'enfant accédant à la table Temp locale des parents, qu'il peut faire sans recourir à l'utilisation du nom complet de Tempdb. Tant que l'enfant ne crée pas de table temporaire en conflit.


Mais je parlais du premier cas - Parent accédant à la table Temp locale de l'enfant. S'il vous plaît jeter un oeil à la citation de votre commentaire :) Il s'agit de parent accéder à la table Temp ...


Votre réponse est déroutante. Je pensais que vous parliez d'exemple de OP où la deuxième procédure est l'enfant, appelée à la première procédure.



2
votes

1) Le système ne devrait-il pas se plaindre lorsque #MyTable est créé à l'intérieur Procédure 2? Je comprends pourquoi il ne peut pas s'opposer au temps de compilation, mais Au moment de l'exécution, je m'attendrais à une erreur.

It fait se plaindre au temps de compilation. Lorsqu'il compile dbo.myproc2 Il voit que la table existe à la portée des parents et n'est pas compatible avec la liste de colonnes que vous utilisez. S'il n'y avait aucun objet parent visible de ce nom, la compilation de cette déclaration aurait été différée jusqu'à ce qu'elle soit exécutée (après la table Create ).

Si vous deviez supprimer le fichier initial à partir de dbo.myproc2 , puis exécutez dbo.myproc2 avant dbo.myproc1 il réussira probablement - comme il aura déjà le plan mis en cache pour dbo.myproc2 et pas besoin de recompiler.

Je ne le recommande pas cependant à moins que vous n'aimez d'erreurs aléatoires lorsque le plan est supprimé du cache et que les procédures sont exécutées dans le mauvais ordre. Mieux utiliser des noms uniques.


1 commentaires

ACK, merci d'avoir souligné mon langage bâclé sur le "temps de compilation". J'aurais dû dire quelque chose comme "lors de la création de procédure survient".



2
votes

1) Le système ne devrait-il pas se plaindre lorsque #MyTable est créé à l'intérieur Procédure 2? Je comprends pourquoi il ne peut pas s'opposer au temps de compilation, mais Au moment de l'exécution, je m'attendrais à une erreur.

Non, ça ne devrait pas. Vous obtiendrez 2 tables temporaires locales voir leurs noms: xxx

sqlfiddledemo

sortie: xxx

2) étant donné qu'il ne se plaignait pas de la création, et en fait quand Vous sélectionnez à partir de #MyTable à l'intérieur de la procédure 2, vous voyez la nouvelle colonne, pourquoi se plaint-il de l'insert?

Parce que SQL Server Obtenez la première définition de table à partir de la procédure stockée extérieure. Il a des colonnes différentes pour que vous obtiendrez une erreur pendant insérer


0 commentaires

6
votes

du Créer une table Documentation:

Une table temporaire locale créée dans une procédure stockée ou un déclencheur peut avoir le même nom qu'un tableau temporaire créé avant que la procédure stockée ou la gâchette soit appelée. Toutefois, si une requête référente une table temporaire et deux tables temporaires avec le même nom existent à cette époque, il n'est pas défini à la table de résolution de la requête. Les procédures stockées imbriquées peuvent également créer des tables temporaires avec le même nom que la table temporaire créée par la procédure stockée qui l'appelait. Toutefois, pour des modifications pour résoudre le tableau créé dans la procédure imbriquée, la table doit avoir la même structure, avec les mêmes noms de colonnes, comme le tableau créé dans la procédure d'appel.


0 commentaires