Exécution en boucle selon les données d'une table
Mon besoin était d'importer des fichiers CSV placé dans un répertoire par un processus d'upload http. Le site web gérant l'upload inscrivait dans une table le chemin et le nom du fichier source. Afin de créer une boucle en DTS, on commence par une étape Execute SQL Task, qui vérifie qu'il existe une entrée dans la table à processer, et qui exécute un RAISERROR si c'est le cas, pour brancher sur le reste du DTS en cas d'erreur. Cela permet de quitter le DTS en succès s'il n'y a rien à faire, et de ne pas générer une erreur de DTS.
IF EXISTS (SELECT TableId FROM dbo.TABLE WHERE STATUS = 1) RAISERROR('allons-y !',16,1)
Une autre solution, comme indiquée ici, consiste à attribuer le résultat d'un COUNT(*) à une variable globale, en utilisant soit une étape Execute SQL ou Dynamic Properties, et ensuite de décider de l'action dans un étape “ActiveX Script” suivante, qui manipule la valeur de retour de l'étape.
La deuxième étape, s'il y a une ligne à traiter, est d'attribuer les valeurs utiles à des variables globales du DTS. Cela s'effectue en utilisant une étape Execute SQL, en faisant un TOP 1 sur la table contenant les infos. Les colonnes retournées sont attribuées aux variables globales dans la fenêtre de paramètres, appelées par le bouton Parameters, onglet Output Parameters. En sélectionnant le type row value, on peut attribuer chaque colonne de retour à un paramètre global.
Troisième étape : A travers une tâche Dynamic Properties, on attribue au DataSource de notre connexion Text File (Source) la valeur de la variable globale contenant le nom et chemin du fichier texte à importer.
Ensuite, l'importation du fichier peut prendre place. Après quoi, pour continuer la boucle, une étape Execute SQL peut changer le statut de la ligne de la table qui a été traitée, en utilisant un Id placé en variable globale comme paramètre d'entrée: posez simplement un ? à la place de la valeur, et attribuez le paramètre dans la fenêtre Parameters
Passage de paramètres globaux à un package fils
Pour passer des paramètres globaux à un package appelé par un package parent, indiquez-les dans les onlgets Inner Package Global Variables et Outer Package Global Variables. Tous les deux servent à attribuer des valeurs au package appelé. La version Inner liste les packages globaux déjà défini dans le package fils, et permet en quelque sorte de coder leur valeur en dur. La version Outer permet d'attribuer la valeur d'une variable globale du package parent au package appelé. Si la variable outer n'existe pas dans le package fils, elle est créée temporairement, en runtime.
Il n'y a pas de mécanisme intégré pour retrouver, dans un package parent, les valeurs de variable d'un package fils. On peut pour se faire utiliser deux méthodes :
- stocker les valeurs dans une table SQL tampon, et les retrouver dans le package parent;
- Utiliser un script ActiveX, avec qqch comme
DTSGlobalVariables.Parent…. Attention, le nom des variables globales est sensible à la casse.
J'ai songé à une façon semi dynamique mais peut-être moyennement élégante de gérer les appels de packages et le passage de paramètres entre eux, dans une situation où j'avais besoin de déterminer selon un critère quel package fils appeler. Mon idée a été de créer une table stockant le critère à tester, l'Id et le nom du package à appeler (ou le nom seulement, voir note au paragraphe suivant), ainsi que des colonnes contenant chaque variable globale à passer et recevoir du package. Ainsi, le package fils est attribué en runtime via une requête sur la table et une tâche Dynamic Properties.
Le Package Id est utilisé par le DTS pour lancer le package seulement si l'Id est renseigné. Sinon le Package Name est utilisé pour retrouver le package, comme indiqué ici. Ca peut donc être une bonne idée de n'utiliser que le package name, notamment pour des problèmes de déploiement. Comme indiqué dans le lien ci-dessus, videz le Package Id avec la fonction disconnected edit… ou en utilisant une tâche Dynamic Properties.
Importation de fichier texte
Pour l'importation dynamique de fichiers textes dans une table SQL, à partir d'une liste de délimiteurs de colonnes, la tâche Dynamic Properties est aussi très utile, en permettant de modifier, dans les OLE DB Properties de la connexion, la Value de la propriété Column Delimiter
dézippage d'une archive
ci-dessous le code d'une tâche vbScript un peu bricolée pour dézipper un fichier (à partir d'un fichier en variable globale)
'********************************************************************** ' Unzip a file. ' not very safe implementation : based on the assumption that there's only ' one file in the zip, and that it is named like the zip file itself. '************************************************************************ option Explicit Function Main() Dim oFSO Dim WshShell, strUnzip, strFile Set oFSO = CreateObject("Scripting.FileSystemObject") strFile = RTrim(DTSGlobalVariables("FILE_PATH").Value) if (Right( strFile , 4 ) = ".zip") and oFSO.FileExists(strFile) then Set WshShell = CreateObject("WScript.Shell") WshShell.CurrentDirectory = oFSO.GetParentFolderName(strFile) strUnzip = """c:\Program Files\7-Zip\7z.exe"" e -y " & strFile WshShell.Run strUnZip,,true Set WshShell = nothing strFile = Replace( strFile , ".zip" , ".csv") if not oFSO.FileExists(strFile) then DTSTaskExecResult_Failure exit Function end DTSGlobalVariables("FILE_PATH").Value = strFile end if Main = DTSTaskExecResult_Success End Function
Boucler dans un package
Ma première tentative était bien sûr d'attacher par workflow la dernière étape à la première. Ce qui gène un peu le DTS apparemment, qui ne sait plus où commencer.
La solution est de terminer par un script ActiveX qui met la première étape en statut waiting. Exemple simple :
Function Main() Dim step set step = DTSGlobalVariables.Parent.Steps("DTSTask_DTSExecuteSQLTask_3") step.ExecutionStatus = DTSStepExecStat_Waiting Main = DTSTaskExecResult_Success End Function
Erreurs
- Type Mismatch dans une tâche Dynamic Properties : un élément récupéré depuis une requête est envoyé à NULL



