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
 
sql_server/dts.txt · Dernière modification: 2006/05/12 17:12 (édition externe)