Fallstrick bei Foreach-Schleifencontainer mit Excel-Dateien

Eigentlich sollte es ganz einfach sein alle Excel-Dateien in einem Verzeichnis mal eben mit einem SSIS-Task in die Datenbank zu pumpen. Nachdem es erst einige Tage funktioniert hat, gab es dann plötzlich Fehler.

Die Fehlermeldung

An OLE DB error has occurred. Error code: 0x80004005.  An OLE DB record is available.  Source: "Microsoft Access Database Engine"  Hresult: 0x80004005  Description: "External table is not in the expected format.".

Interessanterweise trat der Fehler auf dem Server erst seit Juli 2018 auf, auf meinem PC aber erst (nach den letzten WSUS-Updates) im August. Wie äußerte sich der Fehler? Im Verzeichnis lagen z. B. 4 Dateien, nach dem Lauf des Paketes waren diese Inhalte auch in eine Staging-Tabelle importiert, aber das Paket wurde trotzdem mit dem oben beschriebenen Fehler abgebrochen. Okay, dann wird der Fehler wohl in der letzten Datei liegen. Also spielt man nur 3 Dateien ein. Der Fehler bleibt aber der gleiche. Man kann keine einzige der vier Dateien einspielen, obwohl doch der Fehler ursprünglich erst nach der vierten Datei aufgetreten ist.

Was ist passiert?

Nachdem der Fehler auf meinem PC zuverlässig auftrat, konnte ich mit dem Debugger recht schnell der Sache auf den Grund gehen. Der Foreach-Schleifencontainer wurde ausgeführt und rief vier mal meinen Datenfluss-Task auf. Und dann sollte es mit dem nächsten Task nach dem Schleifencontainer weitergehen. Aber es gab noch einen fünften Durchlauf. Fünf Läufe bei vier Dateien? Also schaut man mit dem Debugger mal in die Variablen rein. Die Variable, die den vollqualifizierten Dateinamen enthalten sollte, hat im fünften Lauf plötzlich einen Dateinamen beinhaltet, den es gar nicht (mehr) gab. Normalerweise steht da etwas in dieser Art:

	{D:\\Pfad_der_ vierten_Datei\\Vierte_Datei.xlsx}

aber im fünften Lauf war es dann

	{D:\\Pfad_der_ vierten_Datei\\~$Vierte_Datei.xlsx}

Hier hat uns also die Access Database Engine im Hintergrund mal eben eine Datei angelegt und dem (evtl. auch leicht gekürzten) Dateinamen die beiden Zeichen '~$' vorangestellt. Der Schleifencontainer hat diesen Dateinamen auch noch mal eben mitgenommen, obwohl die Datei eigentlich nicht mehr existieren sollte, denn der Datenflusstask war beendet und die richtige Excel-Datei auch bereits verschoben. Der Zweck dieser im Hintergrund angelegten temporären Datei ist es, den aktuellen Eigentümer (Benutzer) der Daten eindeutig zu definieren.

Siehe auch diese veraltete Dokumentation zu Word-Dateien: Description of how Word creates temporary files

Owner File (Same Directory as Source File)
When a previously saved file is opened for editing, for printing, or for review, Word creates a temporary file that has a .doc file name extension. This file name extension begins with a tilde (~) that is followed by a dollar sign ($) that is followed by the remainder of the original file name. This temporary file holds the logon name of person who opens the file. This temporary file is called the "owner file."

Warum wurde das zum Problem?

Im Foreach-Schleifencontainer wurde als Suchmaske einfach definiert: *.xlsx. Es sollten alle Dateinamen vollqualifiziert verwendet werden und alle Unterordner sollten durchsucht werden.

Der gefundene vollqualifizierte Dateiname sollte dann in die Variable User::Dateiname abgelegt werden.

Eine weitere Einschränkung gab es nicht und mit dieser sehr allgemeinen Suchmaske war dem Fehler Tür und Tor geöffnet.

Wie kann man diesen Fehler abfangen?

Der Ansatzpunkt ist natürlich der Dateiname. Sobald dieser die Kombination von '~$' enthält, soll der Datenflusstask nicht ausgeführt werden. Glücklicherweise habe ich vor dem Datenflusstask noch einen SQL-Task. (Wenn man keinen hat, kann man ja mal einfach einen anlegen, der nichts besonderes macht.) Nach dem SQL-Task wurde jetzt ein Ausdruck eingeführt, der den weiteren Fortgang steuert:

Dieser Ausdruck liefert uns einen Wert TRUE wenn die beiden Zeichen '~$' nicht gefunden werden.

FINDSTRING( @[User::Dateiname],"~$",1 ) < 1

Diese Einschränkung mit FINDSTRING müssen wir jetzt bei der Rangfolgeneinschränkung verwenden. Diese ändern wir dazu vom Standardwert "Erfolg" auf den Wert "Ausdruck". Dort setzen wir dann den oben angegebenen Ausdruck ein.

Beim nächsten Ablauf mit den vier Dateien griff im fünften Durchlauf die Bedingung und der Datenfluss-Task wurde nicht mehr aufgerufen. Es gab keine Fehlermeldung mehr und die weiteren Schritte konnten problemlos ausgeführt werden.

Wenn eine weniger allgemeine Suchmaske für die Excel-Dateien definiert worden wäre, die auch zumindest das erste Zeichen angegeben hätte, wäre dieser Fehler nicht passiert. Aber leider hat man ja nicht immer Einfluss auf die Vergabe von Dateinamen und muss sich manchmal überraschen lassen, was die User sich so überlegt haben.