Analizowanie niestandardowych formatów plików tekstowych za pomocą składnika skryptu

Dotyczy:SQL Server Środowisko SSIS Integration Runtime w usłudze Azure Data Factory

Gdy dane źródłowe są uporządkowane w niestandardowym formacie, może być wygodniej skonsolidować całą logikę parsowania w jednym skrypcie niż łączyć wiele transformacji Integration Services, aby osiągnąć ten sam efekt.

Przykład 1: Parsowanie Row-Delimited rekordów

Przykład 2: Rozdzielanie rekordów nadrzędnych i potomnych

Uwaga / Notatka

Jeśli chcesz stworzyć komponent, który łatwiej będzie Ci powtarzać w wielu zadaniach Przepływ danych i pakietach, rozważ użycie kodu z tego przykładu komponentu skryptowego jako punktu wyjścia dla niestandardowego komponentu data flow. Aby uzyskać więcej informacji, zobacz Tworzenie niestandardowego składnika przepływu danych.

Przykład 1: Parsowanie Row-Delimited rekordów

Ten przykład pokazuje, jak wziąć plik tekstowy, w którym każda kolumna danych pojawia się na osobnej linii, i przetworzyć go do tabeli docelowej za pomocą komponentu Script.

Aby uzyskać więcej informacji o konfiguracji komponentu skryptowego do użycia jako transformacji w przepływie danych, zobacz Tworzenie transformacji synchronicznej z komponentem skryptowym oraz tworzenie transformacji asynchronicznej z komponentem skryptowym.

Aby skonfigurować ten przykład Komponentu Skryptu

  1. Stwórz i zapisz plik tekstowy o nazwie rowdelimiteddata.txt , który zawiera następujące dane źródłowe:

    FirstName: Nancy  
    LastName: Davolio  
    Title: Sales Representative  
    City: Seattle  
    StateProvince: WA  
    
    FirstName: Andrew  
    LastName: Fuller  
    Title: Vice President, Sales  
    City: Tacoma  
    StateProvince: WA  
    
    FirstName: Steven  
    LastName: Buchanan  
    Title: Sales Manager  
    City: London  
    StateProvince:  
    
    
  2. Otwórz Management Studio i połącz się z instancją SQL Server.

  3. Wybierz docelową bazę danych i otwórz nowe okno zapytania. W oknie zapytania wykonaj następujący skrypt, aby utworzyć tabelę docelową:

    create table RowDelimitedData  
    (  
    FirstName varchar(32),  
    LastName varchar(32),  
    Title varchar(32),  
    City varchar(32),  
    StateProvince varchar(32)  
    )  
    
    
  4. Otwórz SQL Server Data Tools i stwórz nowy pakiet Integration Services o nazwie ParseRowDelim.dtsx.

  5. Dodaj menedżera połączeń z plikiem płaskim do pakietu, nazwij go RowDelimitedData i skonfiguruj tak, aby łączył się z plikiem rowdelimiteddata.txt utworzonym w poprzednim kroku.

  6. Dodaj menedżera połączeń OLE DB do pakietu i skonfiguruj go tak, aby łączył się z instancją SQL Server oraz bazą danych, w której utworzyłeś tabelę docelową.

  7. Dodaj zadanie Przepływ danych do pakietu i kliknij zakładkę Przepływ danych w SSIS Designer.

  8. Dodaj Flat File Source do przepływu danych i skonfiguruj go do użycia menedżera połączeń RowDelimitedData. Na stronie Kolumny w edytorze źródeł plików płaskich wybierz jedną dostępną zewnętrzną kolumnę.

  9. Dodaj komponent skryptowy do przepływu danych i skonfiguruj go jako transformację. Połącz wyjście Flat File Source z komponentem skryptowym.

  10. Kliknij dwukrotnie na komponent skryptu, aby wyświetlić edytor transformacji skryptów.

  11. Na stronie Kolumny wejściowe w Edytorze Transformacji Skryptów wybierz pojedynczą dostępną kolumnę wejściową.

  12. Na stronie Wejść i Wyjść w edytorze transformacji skryptów wybierz Wyjście 0 i ustaw jego SynchronousInputID na Brak . Stwórz 5 kolumn wyjściowych, wszystkie o ciągu typu [DT_STR] o długości 32:

    • Imię (pierwsze)

    • LastName

    • Title

    • Miejscowość

    • StateProvince

  13. Na stronie Script w Script Transformation Editor kliknij Edit Script i wpisz kod pokazany w klasie ScriptMain tego przykładu. Zamknij środowisko tworzenia skryptów oraz Edytor Transformacji Skryptów.

  14. Dodaj miejsce docelowe SQL Server do przepływu danych. Konfiguruj go tak, aby korzystał z menedżera połączeń OLE DB oraz tabeli RowDelimitedData. Połącz wyjście komponentu skryptowego z tym celem.

  15. Uruchom pakiet. Po zakończeniu pakietu przejrzyj rekordy w tabeli docelowej SQL Server.

Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)  
  
    Dim columnName As String  
    Dim columnValue As String  
  
    ' Check for an empty row.  
    If Row.Column0.Trim.Length > 0 Then  
        columnName = Row.Column0.Substring(0, Row.Column0.IndexOf(":"))  
        ' Check for an empty value after the colon.  
        If Row.Column0.Substring(Row.Column0.IndexOf(":")).TrimEnd.Length > 1 Then  
            ' Extract the column value from after the colon and space.  
            columnValue = Row.Column0.Substring(Row.Column0.IndexOf(":") + 2)  
            Select Case columnName  
                Case "FirstName"  
                    ' The FirstName value indicates a new record.  
                    Me.Output0Buffer.AddRow()  
                    Me.Output0Buffer.FirstName = columnValue  
                Case "LastName"  
                    Me.Output0Buffer.LastName = columnValue  
                Case "Title"  
                    Me.Output0Buffer.Title = columnValue  
                Case "City"  
                    Me.Output0Buffer.City = columnValue  
                Case "StateProvince"  
                    Me.Output0Buffer.StateProvince = columnValue  
            End Select  
        End If  
    End If  
  
End Sub  
public override void Input0_ProcessInputRow(Input0Buffer Row)  
    {  
  
        string columnName;  
        string columnValue;  
  
        // Check for an empty row.  
        if (Row.Column0.Trim().Length > 0)  
        {  
            columnName = Row.Column0.Substring(0, Row.Column0.IndexOf(":"));  
            // Check for an empty value after the colon.  
            if (Row.Column0.Substring(Row.Column0.IndexOf(":")).TrimEnd().Length > 1)  
            // Extract the column value from after the colon and space.  
            {  
                columnValue = Row.Column0.Substring(Row.Column0.IndexOf(":") + 2);  
                switch (columnName)  
                {  
                    case "FirstName":  
                        // The FirstName value indicates a new record.  
                        this.Output0Buffer.AddRow();  
                        this.Output0Buffer.FirstName = columnValue;  
                        break;  
                    case "LastName":  
                        this.Output0Buffer.LastName = columnValue;  
                        break;  
                    case "Title":  
                        this.Output0Buffer.Title = columnValue;  
                        break;  
                    case "City":  
                        this.Output0Buffer.City = columnValue;  
                        break;  
                    case "StateProvince":  
                        this.Output0Buffer.StateProvince = columnValue;  
                        break;  
                }  
            }  
        }  
  
    }  

Przykład 2: Rozdzielanie rekordów nadrzędnych i potomnych

Ten przykład pokazuje, jak wziąć plik tekstowy, w którym wiersz separatora poprzedza wiersz rekordu nadrzędnego, po którym następuje nieokreślona liczba wierszy rekordu potomnego, i rozłożyć go na poprawnie znormalizowane tabele docelowe rodzica i dziecka za pomocą komponentu Script. Ten prosty przykład można łatwo zaadaptować dla plików źródłowych, które używają więcej niż jednego wiersza lub kolumny dla każdego nadrzędnego i potomnego rekordu, pod warunkiem, że istnieje sposób na identyfikację początku i końca każdego rekordu.

Caution

Ta próbka służy wyłącznie do celów demonstracyjnych. Jeśli uruchomisz próbkę więcej niż raz, wstawia ona zduplikowane wartości klucza do tabeli docelowej.

Aby uzyskać więcej informacji o konfiguracji komponentu skryptowego do użycia jako transformacji w przepływie danych, zobacz Tworzenie transformacji synchronicznej z komponentem skryptowym oraz tworzenie transformacji asynchronicznej z komponentem skryptowym.

Aby skonfigurować ten przykład Komponentu Skryptu

  1. Stwórz i zapisz plik tekstowy o nazwie parentchilddata.txt , który zawiera następujące dane źródłowe:

    **********  
    PARENT 1 DATA  
    child 1 data  
    child 2 data  
    child 3 data  
    child 4 data  
    **********  
    PARENT 2 DATA  
    child 5 data  
    child 6 data  
    child 7 data  
    child 8 data  
    **********  
    
    
  2. Otwórz SQL Server Management Studio i połącz się z instancją SQL Server.

  3. Wybierz docelową bazę danych i otwórz nowe okno zapytania. W oknie zapytania wykonaj następujący skrypt, aby utworzyć tabele docelowe:

    CREATE TABLE [dbo].[Parents]([ParentID] [int] NOT NULL,  
    [ParentRecord] [varchar](32) NOT NULL,  
     CONSTRAINT [PK_Parents] PRIMARY KEY CLUSTERED   
    ([ParentID] ASC))  
    GO  
    CREATE TABLE [dbo].[Children]([ChildID] [int] NOT NULL,  
    [ParentID] [int] NOT NULL,  
    [ChildRecord] [varchar](32) NOT NULL,  
     CONSTRAINT [PK_Children] PRIMARY KEY CLUSTERED   
    ([ChildID] ASC))  
    GO  
    ALTER TABLE [dbo].[Children] ADD CONSTRAINT [FK_Children_Parents] FOREIGN KEY([ParentID])  
    REFERENCES [dbo].[Parents] ([ParentID])  
    
    
  4. Otwórz SQL Server Data Tools (SSDT) i stwórz nowy pakiet Integration Services o nazwie SplitParentChild.dtsx.

  5. Dodaj menedżera połączeń z plikami płaskimi do pakietu, nazwij go ParentChildData i skonfiguruj tak, aby łączył się z plikiem parentchilddata.txt, który utworzyłeś w poprzednim kroku.

  6. Dodaj menedżera połączeń z OLE DB do pakietu i skonfiguruj go tak, aby łączył się z instancją SQL Server oraz bazą danych, w której stworzyłeś tabele docelowe.

  7. Dodaj zadanie Przepływ danych do pakietu i kliknij zakładkę Przepływ danych w SSIS Designer.

  8. Dodaj Flat File Source do przepływu danych i skonfiguruj go do korzystania z menedżera połączeń ParentChildData. Na stronie Kolumny w edytorze źródeł plików płaskich wybierz jedną dostępną zewnętrzną kolumnę.

  9. Dodaj komponent skryptowy do przepływu danych i skonfiguruj go jako transformację. Połącz wyjście Flat File Source z komponentem skryptowym.

  10. Kliknij dwukrotnie na komponent skryptu, aby wyświetlić edytor transformacji skryptów.

  11. Na stronie Kolumny wejściowe w Edytorze Transformacji Skryptów wybierz pojedynczą dostępną kolumnę wejściową.

  12. Na stronie Inputs and Outputs w Script Transformation Editor wybierz Output 0, przemianuj go na ParentRecords i ustaw SynchronousInputID na None. Stwórz 2 kolumny wyjściowe:

    • ParentID (klucz główny), czterobajtowy znak całkowity [DT_I4]

    • ParentRecord, o typie string [DT_STR] o długości 32.

  13. Stwórz drugi wynik i nazwij go ChildRecords. SynchronousInputID nowego wyjścia jest już ustawione na Zero. Stwórz 3 kolumny wyjściowe:

    • ChildID (klucz główny), czterobajtowy znak całkowity [DT_I4]

    • ParentID (klucz obcy), również czterobajtowy znak całkowity [DT_I4]

    • ChildRecord, o typie string [DT_STR] o długości 50

  14. Na stronie skryptu w edytorze transformacji skryptów kliknij Edytuj skrypt. W klasie ScriptMain wpisz kod pokazany w przykładzie. Zamknij środowisko tworzenia skryptów oraz Edytor Transformacji Skryptów.

  15. Dodaj miejsce docelowe SQL Server do przepływu danych. Połącz wyjście ParentRecords komponentu skryptowego z tym miejscem. Konfiguruj go tak, aby korzystał z menedżera połączeń OLE DB oraz tabeli rodziców.

  16. Dodaj kolejny SQL Server Destination do przepływu danych. Połącz wyjście ChildRecords komponentu skryptowego do tego miejsca docelowego. Konfiguruj go tak, aby korzystał z menedżera połączeń OLE DB oraz tabeli dzieci.

  17. Uruchom pakiet. Po zakończeniu pakietu przejrzyj rekordy rodzica i potomne w dwóch tabelach docelowych SQL Server.

Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)  
  
    Static nextRowIsParent As Boolean = False  
    Static parentCounter As Integer = 0  
    Static childCounter As Integer = 0  
  
    ' If current row starts with separator characters,  
    '  then following row contains new parent record.  
    If Row.Column0.StartsWith("***") Then  
        nextRowIsParent = True  
    Else  
        If nextRowIsParent Then  
            ' Current row contains parent record.  
            parentCounter += 1  
            Me.ParentRecordsBuffer.AddRow()  
            Me.ParentRecordsBuffer.ParentID = parentCounter  
            Me.ParentRecordsBuffer.ParentRecord = Row.Column0  
            nextRowIsParent = False  
        Else  
            ' Current row contains child record.  
            childCounter += 1  
            Me.ChildRecordsBuffer.AddRow()  
            Me.ChildRecordsBuffer.ChildID = childCounter  
            Me.ChildRecordsBuffer.ParentID = parentCounter  
            Me.ChildRecordsBuffer.ChildRecord = Row.Column0  
        End If  
    End If  
  
End Sub  
public override void Input0_ProcessInputRow(Input0Buffer Row)  
    {  
  
    int static_Input0_ProcessInputRow_childCounter = 0;  
    int static_Input0_ProcessInputRow_parentCounter = 0;  
    bool static_Input0_ProcessInputRow_nextRowIsParent = false;  
  
        // If current row starts with separator characters,   
        // then following row contains new parent record.   
        if (Row.Column0.StartsWith("***"))  
        {  
            static_Input0_ProcessInputRow_nextRowIsParent = true;  
        }  
        else  
        {  
            if (static_Input0_ProcessInputRow_nextRowIsParent)  
            {  
                // Current row contains parent record.   
                static_Input0_ProcessInputRow_parentCounter += 1;  
                this.ParentRecordsBuffer.AddRow();  
                this.ParentRecordsBuffer.ParentID = static_Input0_ProcessInputRow_parentCounter;  
                this.ParentRecordsBuffer.ParentRecord = Row.Column0;  
                static_Input0_ProcessInputRow_nextRowIsParent = false;  
            }  
            else  
            {  
                // Current row contains child record.   
                static_Input0_ProcessInputRow_childCounter += 1;  
                this.ChildRecordsBuffer.AddRow();  
                this.ChildRecordsBuffer.ChildID = static_Input0_ProcessInputRow_childCounter;  
                this.ChildRecordsBuffer.ParentID = static_Input0_ProcessInputRow_parentCounter;  
                this.ChildRecordsBuffer.ChildRecord = Row.Column0;  
            }  
        }  
  
    }