J'ai écrit une procédure stockée pour importer et transformer des données d'une base de données à une autre. Chaque importation prendrait un ID d'entreprise unique et importerait toutes les données relatives à cette entreprise.
Pour aider à l'étape de transformation, j'utilise des tables temporaires. Dans le cadre de la révision du script, on m'a dit d'utiliser des variables de table plutôt que des tables temporaires. Le réviseur affirme que si nous exécutons deux importations différentes en même temps, la table temporaire serait partagée et corromprait l'importation.
Questions:
EXEC
crée-t-il une nouvelle étendue?Voici un exemple artificiel du script.
CREATE PROC [dbo].[ImportCompany]
(
@CompanyId AS INTEGER
)
AS
EXEC [dbo].[ImportAddress] @CompanyId = @CompanyId
--Import other data
CREATE PROC [dbo].[ImportAddress]
(
@CompanyId AS INTEGER
)
AS
CREATE TABLE #Companies (OldAddress NVARCHAR(128), NewAddress NVARCHAR(128))
INSERT INTO #Companies(OldAddress, NewAddress)
SELECT
Address as OldAddress,
'Transformed ' + Address as NewAddress
FROM
[OldDb].[dbo].[Addresses]
WHERE
CompanyId = @CompanyId
--Do stuff with the transformed data
DROP TABLE #Companies
EXEC [dbo].[ImportCompany] @CompanyId = 12345
De CREATE TABLE
:
Les tables temporaires locales ne sont visibles que dans la session en cours
et plus important):
Si une table temporaire locale est créée dans une procédure stockée ou une application qui peut être exécutée en même temps par plusieurs utilisateurs, le moteur de base de données doit pouvoir distinguer les tables créées par les différents utilisateurs [ sic - cela devrait presque certainement dire que les sessions ne sont pas des utilisateurs] . Le moteur de base de données le fait en ajoutant en interne un suffixe numérique à chaque nom de table temporaire locale.
Ce qui réfute exactement le point de savoir qui a dit qu'ils seraient partagés.
De plus, il n'est pas nécessaire de DROP TABLE
à la fin de votre procédure (à partir du même lien):
Une table temporaire locale créée dans une procédure stockée est supprimée automatiquement lorsque la procédure stockée est terminée
##
est utilisé pour les tables temporaires globales - sera disponible pour les différentes importations.
#
est utilisé pour les tables temporaires locales et n'est disponible que dans la portée actuelle/interne.
Une session ne peut pas voir les tables temporaires d'une autre session. Ainsi, les importations différentes ne s'influenceront pas, que vous utilisiez des tables temporaires ou des variables de table.
L'exception concerne les tables temporaires globales, qui commencent par ##
. Ceux-ci sont visibles par toutes les connexions.
Je viens de passer quelques heures à essayer de comprendre pourquoi une table temporaire utilisée dans un déclencheur s'est comportée étrangement. Ensuite, j'ai réalisé que la table temporaire avait le même nom qu'une table temporaire dans la procédure stockée utilisée pour insérer les données qui ont déclenché le déclencheur. Je suis maintenant conscient que cela aurait dû être évident pour moi tout de suite, mais c'était un cas typique de négliger la cause la plus évidente en essayant de découvrir pourquoi quelque chose n'avait pas de sens.
Il est donc important de se rappeler que lorsqu'un proc stocké appelle un autre proc stocké ou déclenche un déclencheur, les noms des tables temporaires doivent être uniques entre eux afin d'éviter les effets secondaires indésirables.
De plus - même lors de l'exécution du code suivant dans le processus interne stocké, il ne fonctionnera pas comme prévu. Puisque le proc externe stocké semble verrouiller le nom de la table temporaire.
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
DROP TABLE #TempTable