web 2.0

SSIS: CSV-Dateien mit Textbegrenzungszeichen innerhalb des Textes importieren

Damit man Sonderzeichen innerhalb der Daten einer CSV-Datei nutzen kann, gibt es Textbegrenzungszeichen (engl.: text qualifier). Soll dieses Begrenzerzeichen in den Daten vorkommen, so wird dieses einfach verdoppelt (maskiert). Nachfolgend eine Beispieldatei mit dem “ als Textbegrenzungszeichen:

1|"John Doe"|17.01.1946
2|"Dwayne ""The Rock"" Johnson"|02.05.1972
3|"Steve ""Stone Cold"" Austin"|18.12.1964
4|"Randy ""Macho Man"" Savage"|15.11.1952
5|"Hulk Hogan"|11.10.1953
6|"Mark "The Undertaker" Calaway"|24.03.1965

Fügt man einen Verbindungsmanger für die CSV-Datei hinzu und wählt das doppelte Anführungszeichen(“)als “Text qualifier” aus

1 Flat File Connection Manager Editor

dann kommt es beim Wechsel auf Columns zu folgender Fehlermeldung:

2 Error

Ignoriert man diese Meldung und führt das Paket trotzdem aus, schlägt dieses fehl mit der Meldung:

[SSIS.Pipeline] Error: SSIS-Fehlercode 'DTS_E_PRIMEOUTPUTFAILED'. Die PrimeOutput-Methode in 'Komponente 'Flatfilequelle' (1)' hat den Fehlercode 0xC0202092 zurückgegeben. Die Komponente gab einen Fehlercode zurück, als das Pipelinemodul 'PrimeOutput()' aufgerufen hat. Die Bedeutung des Fehlercodes wird von der Komponente definiert. Der Fehler ist jedoch schwerwiegend, und die Ausführung der Pipeline wurde beendet. Möglicherweise wurden bereits Fehlermeldungen veröffentlicht, die weitere Fehlerinformationen beinhalten.

Damit ist klar, SSIS unterstütz keine Textbegrenzungszeichen innerhalb eines Datenfeldes (zumindest bis einschließlich der Version für SQL Server 2008).

Wichtig: Als Workaround zeige ich jetzt einen kleinen Trick, der allerdings nur hilft, wenn das Spaltentrennzeichen nicht im Text vorkommt.

Als erstes entfernt man das Textbegrenzungszeichen  im Verbindungsmanager für die CSV-Datei. Würde man dann die Daten in eine Datenbank importieren, würde man dieses Ergebnis sehen:

3 unerwuenschtes Ergebnis

Hier sind jetzt natürlich eine Menge Anführungszeichen zu sehen. Innerhalb des Textes kommen diese auch doppelt vor, was so nicht beabsichtigt ist. Deshalb führt man im Datenflusstask eine Abgeleitete Spalte (engl.: derived column) hinzu. Damit kann man die Daten in der Spalte mit diversen Funktionen bearbeiten.

4 Datenfluss

Zuvor benötigt man noch zwei Variablen, auf die ich gleich noch einmal zurückkomme.

5 Variablen

Jetzt ist alles vorbereitet und man kann den Transformationstask “Abgeleitete Spalte” bearbeiten. Dort wird unter Derived Column die zu bearbeitende Spalte ausgewählt und bei Expression folgender Wert eingegeben:

REPLACE(SUBSTRING([Column 1],2,LEN([Column 1]) - 2),@[User::q1],@[User::q2])

Im Prinzip wird hier nur der String am Anfang und Ende beschnitten (die Anführungszeichen entfernt) und doppelte Vorkommen durch ein Anführungszeichen ersetzt.

Das Ganze sieht dann so aus:

6 Derived Column Transformation Editor

Führt man jetzt das Paket aus, erscheint folgendes Ergebnis:

7 Ergebnis

Die Anführungszeichen am Anfang und Ende sind verschwunden und innerhalb des Textes kommen diese nur noch einfach vor.

Hinweis: Anscheinend kommt es nur bei Dateien im Unicode-Format zu diesen Fehler. Bei einem Test mit einer ANSI-Datei lief alles fehlerlos.

Tags:

SSIS | Datenbanken

SSIS: Importieren von CSV-Dateien mit unterschiedlicher Spaltenanzahl

Der Import von CSV-Dateien in eine Datenbank stellt ein paar Tücken bereit. Nicht immer hat man die volle Kontrolle über die CSV-Datei. Besonders wenn die Daten von einem Fremdanbieter kommen, der nicht so auf die Qualität seiner Daten achtet. Da kann es schon mal vorkommen, dass die Spaltenanzahl in den Zeilen abweicht oder durch falsches Escaping von Trennzeichen(Delimeter) erst gar nicht richtig erkannt werden.

In meinem Beispiel verwende ich eine Datei mit Komma als Spaltentrennzeichen:

1,Wert1,01.01.2001
2,Wert2,12.06.1999
3,Wert3
4,Wert4,31.01.2002
5,Wert5,01.01.2011
6,Wert6
7,Wert7
8,Wert8,24.12.1953
9,Wert9,15.09.1988
10,Wert10

Würde man diese Datei mit den Standardeinstellungen importieren, käme die folgende Zuordnung heraus:

1 falsche Zuordnung

Um dieses Problem zu umgehen, gibt es einen Workaround: Man importiert die CSV-Datei komplett als eine Spalte und extrahiert sich anschließend per Transformationstask die vorhandene Spalten.

Hierfür löscht man im Connection-Manager für die CSV-Datei alle erkannten Spalten und legt eine einzelne neue Spalte an. Da in CSV-Dateien durchaus auch größere Daten vorkommen können (z.B. Beschreibungstexte), wähle ich Textdatenstrom als Datentyp. Daher muss später im Skript-Task auch noch eine Konvertierung vorgenommen werden.

2 eine Spalte

Daraus ergibt sich folgende Zuordnung:

3  Zuordnung mit einer Spalte

Jetzt kann man einen Datenflusstask anlegen, der wie folgt aussehen könnte:

4 Datenflusstask

Im Transformationstask muss dann die zuvor festgelegte Spalte aus dem Verbindungsmanager als Input definiert werden:

5 Input

Des weiteren müssen die Ausgabespalten für den Transformationstask definiert werden:

6 Output

Das Skript für den Transformationstask sieht wie folgt aus:

   1:  public class ScriptMain : UserComponent
   2:  {
   3:   
   4:      private char[] columnDelimiter = new char[] { ',' };
   5:   
   6:      public override void Eingabe0_ProcessInputRow(Eingabe0Buffer Row)
   7:      {
   8:          string[] columnValues = null;
   9:   
  10:          var blobLen = Convert.ToInt32(Row.Line.Length);
  11:          byte[] blobBytes = new byte[blobLen];
  12:          blobBytes = Row.Line.GetBlobData(0, blobLen);
  13:   
  14:          string line = System.Text.Encoding.Unicode.GetString(blobBytes);
  15:          columnValues = line.Split(columnDelimiter);
  16:   
  17:          // Test Correct number of rows
  18:          if (columnValues.Length == 3)
  19:          {
  20:              // Row is OK, output values
  21:              Row.Column1 = columnValues.GetValue(0).ToString();
  22:              Row.Column2 = columnValues.GetValue(1).ToString();
  23:              Row.Column3 = columnValues.GetValue(2).ToString();
  24:          }
  25:          else
  26:          {
  27:              //Row is not complete - Handle error
  28:              Row.Column1_IsNull = true;
  29:              Row.Column2_IsNull = true;
  30:              Row.Column3_IsNull = true;
  31:          }
  32:      }
  33:  }

In der columnDelimeter-Variable wird das Spaltentrennzeichen definiert. Da ich für den Eingabeparameter Line den Datentyp Textdatenstrom  gewählt habe ist Row.Line vom Typ Microsoft.SqlServer.Dts.Pipeline.BlobColumn. Dieser wird in den Zeilen 10 –14 in einen String umgewandelt und kann anschließend per Split-Funktion geteilt werden. Ist die korrekte Anzahl an Spalten vorhanden (in meinem Fall 3), werden die Daten an die Ausgabeparameter übergeben. Andernfalls werden NULL-Werte zurückgegeben.

Die Daten importiert in eine Datenbank liefern folgendes Ergebnis:

7 Ergebnis

Alle Zeilen, die nicht die korrekte Anzahl an Spalten haben werden ignoriert und es werden NULL-Werte in die Datenbank geschrieben. Dieses Verhalten kann man natürlich im Skript-Task nach seinen Wünschen anpassen.

Tags:

SSIS | Datenbanken

IIS: UNC-Pfad als virtuelles Verzeichnis anlegen

Ich hatte letztens ein kleines Problem mit dem IIS. Ich sollte eine CDN-Light-Version entwickeln. Dabei sollte eine Freigabe eines Fileservers als virtuelles Verzeichnis im IIS eingebunden werden. Zum Testen nutzte ich den lokalen IIS (Version 7.5) auf meinem Rechner.  Dieser befindet sich in einer Domäne. Leider ist der Fileserver nicht in der Domäne sondern nur in einer Arbeitsgruppe.

Da beide Rechner nicht zusammen in einer Domäne sind, muss auf beiden Rechnern (Fileserver und Webserver) der gleiche Benutzer mit demselben Passwort angelegt werden. In meinem Beispiel nennen wir ihn UNCUser.

Wichtig: Dieser User muss sowohl Freigabeberechtigungen wie auch NTFS-Berechtigungen für die Freigabe auf dem Fileserver haben.

Da jetzt alle Vorkehrungen getroffen sind, können wir jetzt das virtuelle Verzeichnis anlegen. Hierfür starten wir den den IIS-Manager und wählen aus dem Kontextmenu der Website den Punkt “Virtuelles Verzeichnis hinzufügen … ” aus.

1 IIS

In dem folgenden Dialog können dann die Daten für das virtuelle Verzeichnis eingeben: der Alias und der Physikalische Pfad in UNC-Form (\\<Fileservername>\<Freigabename>).

2 virtuelles Verzeichnis

Da sich der physikalische Pfad in meinem Beispiel auf einem anderen Rechner befindet, wählen wir jetzt “Verbinden als …” aus.

3 verbinden als

In diesem Dialog werden die Credentials für den Zugriff auf die Freigabe angegeben. Wichtig ist hierbei, dass der Benutzername ohne Rechnername eingetragen wird. Also nicht in der Form <Fileserver>\UNCUser oder <Webserver>\UNCUser (wobei <Fileserver> und <Webserver> die entsprechenden Namen der Server sind).

Hinweis: Mit Eingabe des Rechnernamens klappt zwar das Anlegen des virtuellen Verzeichnis, aber bei einem Aufruf der Website kommt es zu Berechtigungsfehlern (z.B. 0x80070003 und 0x8007052e).

4 Credentials

Jetzt muss man nur noch die offenen Dialoge mit “OK” bestätigen und das virtuelle Verzeichnis ist eingerichtet.

Tags:

IIS