1

私は多くの場所を検索しましたが、投稿にフォーラムを使用することはめったにありません...したがって、ここにはまれな問題があると思います。1 対多の関係を含む csv ファイルがあります。たとえば、最初の 10 フィールドには 1 つのレコードが含まれます。これは空白のフィールドに続き、追加の各フィールド内には、フィールドを含むパイプである別の区切り文字があります。これは実際には、1 回の呼び出しに関連して発生したイベントのログ ファイルです。

例えば。

ID;MACHINEID;AN​​I;; コマンド|引数|20120112.06:15:32

太字のテキストは、何度もまたは数回繰り返すことができます。これは、SQL の結合の多側です。これを SQL に戻す必要があります。SSIS スクリプト ブロックを考えています。片側から ID を使用して、ループして多数のテーブルに追加する場所。区切り文字としてパイプを使用して内部フィールドを分割します。誰かがこれを以前に見たことがあり、おそらく私が知らない簡単な解決策を持っているのではないかと思います. これは XML で作成したほうがよいと思いますが、残念ながらそうではありません。

どんな助けでも大歓迎です。ほとんどが建設的なものであれば、批判も受け付けます。よろしくお願いします。

テーブルメイクを見せる

CREATE TABLE [dbo].[tblIVRCalls](
    [CALLID] [char](50) NOT NULL,
    [MACHINEID] [char](50) NOT NULL,
    [CHANNEL] [char](50) NOT NULL,
    [DNIS] [char](50) NOT NULL,
    [ANI] [char](50) NOT NULL,
    [STARTTIME] [smalldatetime] NOT NULL,
    [TRUNK] [char](50) NOT NULL,
    [APPLICATION] [char](50) NULL,
    [PLANID] [char](50) NULL,
    [DERIVEDID] [char](50) NULL,
    [TOTALTIME] [smalldatetime] NOT NULL,
 CONSTRAINT [PK_tblIVRCalls] PRIMARY KEY CLUSTERED 

CREATE TABLE [dbo].[IVRCallActions](
    [pk] [bigint] IDENTITY(1,1) NOT NULL,
    [fkCALLID] [char](50) NOT NULL,
    [SequenceNumber] [bigint] NOT NULL,
    [Command] [char](50) NOT NULL,
    [Arguments] [varchar](max) NOT NULL,
    [ExecutionTime] [datetime] NOT NULL,
 CONSTRAINT [PK_IVRCallActions] PRIMARY KEY CLUSTERED 
4

3 に答える 3

0

1つのオプションは、データをステージングテーブルにインポートすることです。このテーブルでは、繰り返される要素がvarchar(max)(または純粋主義者の場合はnvarchar(max))として格納されます。

次に、次の手順を実行します。

  1. 繰り返されないフィールドを表1に挿入します。
  2. @@ Identityを使用して、挿入したばかりの行のIDをキャプチャします
  3. 繰り返しフィールドをループし、最初に行(区切り文字で定義)を抽出し、次に行のコンポーネント( "|"で定義)を抽出します。
  4. (2)のIDを使用して、各行をテーブル2に挿入します。

ステップ(3)は最も簡単なことではないことを認めます。ただし、ストアドプロシージャを記述し、分割関数(http://stackoverflow.com/questions/2647/split-string-in-sql)を使用する場合は、実行可能です。

私の経験では、複雑な文字列操作は数百メガバイトまで問題なく機能します。一度に複数のギガバイトを処理する必要がある場合は、おそらくカスタムコードが必要になります。

于 2012-05-02T18:28:46.330 に答える
0

元のファイルから2つのファイルを取得するために、コンソールプログラム(C#、vbs、または使用できるものなら何でも)を作成することをお勧めします。

次に、SSISで両方のファイルを処理できます。これは、空のフィールドの管理、データ型の変更などに非常に優れています。

プログラムは、元のファイルを1行ずつ読み取り、それを処理して親行と関連する子行を取得し、一方のファイルに親を、もう一方のファイルに子を書き込みます。これらのファイルは、SSISパッケージのエントリになります。

してはいけないこと:

  • この種のプロセスを作成することは、文字列を処理できる関数が多くないT-SQLでははるかに困難です。
  • SSISでこれを行うことはできません。行を複数の行に分解できるコンポーネントはありません。言うまでもなく、2つの異なる種類の行を生成する必要があります。(カスタムSSISコンポーネントがそれを行いますが、努力する価値はありません)
于 2012-05-02T23:09:49.223 に答える
0

SSISデザインパターン:可変長行のロードで見つかった情報に基づいて、以下の手順を作成することができました。SSISスクリプトブロックは、C#で実行できるすべてのことを実行でき、SQLServerにインストールして設定された間隔で実行できます。処理用に2つの出力を作成しました。このスクリプトを使用して、それぞれのバッファーを埋めます。つまり、1つの列を持つ1つのフラットファイルです。2つの出力とその間のこのスクリプト。

    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        IVRCallsBuffer.AddRow();
        string[] splitEntireRow = null;
        var byteRow = Row.Column0.GetBlobData(0,(int)Row.Column0.Length);
        var entireRow = System.Text.Encoding.ASCII.GetString(byteRow);
        splitEntireRow = entireRow.Split(';');
        int fieldPosition = 0;
        string CallID = "";
        while (splitEntireRow[fieldPosition] != "")
        {
            var splitIVRCall = splitEntireRow[fieldPosition].Split('=');
            switch (splitIVRCall[0])
            {
                case "CALLID":
                    IVRCallsBuffer.CALLID = splitIVRCall[1];
                    CallID = splitIVRCall[1];
                    break;
                case "MACHINEID":
                    IVRCallsBuffer.MACHINEID = splitIVRCall[1];
                    break;
                case "CHANNEL":
                    IVRCallsBuffer.CHANNEL = splitIVRCall[1];
                    break;
                case "DNIS":
                    IVRCallsBuffer.DNIS = splitIVRCall[1];
                    break;
                case "ANI":
                    IVRCallsBuffer.ANI = splitIVRCall[1];
                    break;
                case "STARTTIME":
                    IVRCallsBuffer.STARTTIME = DateTime.ParseExact(splitIVRCall[1], "yyyyMMdd.HH:mm:ss.fff", System.Globalization.CultureInfo.CurrentUICulture);
                    break;
                case "TRUNK":
                    IVRCallsBuffer.TRUNK = splitIVRCall[1];
                    break;
                case "APPLICATION":
                    IVRCallsBuffer.Application = splitIVRCall[1];
                    break;
                case "PLANID":
                    IVRCallsBuffer.PLANID = splitIVRCall[1];
                    break;
                case "DERIVEDID":
                    IVRCallsBuffer.DERIVEDID = splitIVRCall[1];
                    break;
                case "TOTALTIME":
                    IVRCallsBuffer.TOTALTIME = DateTime.ParseExact(splitIVRCall[1],"mm:ss.fff",System.Globalization.CultureInfo.CurrentUICulture);
                    break;   
            }
            fieldPosition++;
        }
        fieldPosition++;
        uint sequence = 1;
        while (splitEntireRow.GetUpperBound(0) -1 > fieldPosition)
        {
            IVRCallActionsBuffer.AddRow();
            var splitIVRCallAction = splitEntireRow[fieldPosition].Split('|');
            IVRCallActionsBuffer.fkCALLID = CallID;
            IVRCallActionsBuffer.SequenceNumber = sequence;
            IVRCallActionsBuffer.Command = splitIVRCallAction[0];
            IVRCallActionsBuffer.Arguments = splitIVRCallAction[1];
            IVRCallActionsBuffer.ExecutionTime = DateTime.ParseExact(splitIVRCallAction[2],"yyyyMMdd.HH:mm:ss.fff", System.Globalization.CultureInfo.CurrentUICulture);
            fieldPosition++;
            sequence++;
        }

    }
}
于 2012-05-03T17:49:47.180 に答える