4

SQL Server Integration Services 2012 の Expression Editor にある TOKEN() という新しい文字列関数で問題が発生しました。

これは、区切られたレコードを解析するのに役立つはずです。レコードがフラット ファイルから出力される場合は、フラット ファイル ソースを使用してこれを行うことができます。この場合、データベースの VARCHAR フィールドに文字列として保存された古い区切りインポート レコードを扱っています。ここで、それらを抽出し、マッサージして、区切り文字列として再エクスポートする必要があります。例えば:

1^リンゴ^0001^01/01/2010^アリクイ^A1
2^バナナ^0002^03/15/2010^クマ^B2
3^クランベリー^0003^4/15/2010^カラス^C3

これらの文字列が OldImportRecord という列にあり、区切り文字がキャレット (示されているように) であり、5 番目のフィールドを派生列に入れたい場合は、次のような式を使用します。

TOKEN(OldImportRecord,"^",5)

これは Anteater、Bear、Crow などを返します。実際、このレコードのフィールドごとに派生列を作成し (インデックスは 1 ベースであることに注意してください)、必要に応じてそれらを変更し、エクスポート用に別の区切りレコードを作成できます。 .

これが問題です。一部のデータに空の文字列 (または空の文字列としてレンダリングされた Null) が含まれている場合はどうなるでしょうか?

4^^0004^6/15/2010^ダック^D4

TOKEN() は、隣接する列区切り文字を数えることができず、列数がずれます。現在は、6 列ではなく 5 列しか表示されません。TOKEN(OldImportRecord,"^",5) は、意図した "Duck" ではなく "D4" を返します。4 番目の列を抽出すると、"Duck" を Date 列に入れようとすることになり、さまざまな楽しみが生じます。

部分的な回避策は次のとおりです。

TOKEN(REPLACE(OldImportRecord,"^^","^ ^"),"^",5)

これは 1 秒おきの区切り文字ペアを欠いていることに注意してください。そのため、REPLACE() の後の "5^ ^^ ^Emu^E5" のように見える "5^^^^Emu^E5" のような文字列では失敗します。列数はまだ間違っています。

だからここに私の完全な回避策があります。これには、ネストされた 2 つの REPLACE ステートメント ()、不要なスペースを削除するための RTRIM()、および結果を VARCHAR に保持したいための DT_STR キャストが含まれます。

(DT_STR,255,1252)RTRIM(TOKEN(REPLACE(REPLACE(OldImportRecord,"^^","^ ^"),"^^","^ ^"),"^",5))

他の人もこの問題に遭遇する可能性があるため、情報としてこれを投稿しています。

誰かがより良い回避策、または実際の解決策を持っていますか?

4

2 に答える 2

2

問題の理由:

TOKENSSIS のメソッドは、 C++strtokの関数の実装を使用します。Microsoft® SQL Server® 2012 Integration Servicesという本を読みながら、この情報を収集しました。113ページのメモとして言及されています(私はこの本が好きです!たくさんの素敵な情報です。)。

関数の実装を検索したstrtokところ、次のリンクが見つかりました。

INFO: strtok(): C Function -- Documentation Supplement - このリンクのコード サンプルは、関数が連続する区切り文字を無視することを示しています。

次の SO の質問に対する回答は、strtok関数が連続した区切り文字を無視するように設計されていることを示しています。

strtok() を使用して 2 つのトークン セパレーターの間にデータが表示されない場合を知る必要があります。

区切り文字が連続する場合の strtok_s の動作

TOKENおよび関数は設計どおりに機能していると思いますが、TOKENCOUNTそれが SSIS の動作方法であるかどうかは、Microsoft SSIS チームにとって問題になる可能性があります。

元の投稿 - 上記のセクションは更新です:

データ入力に基づいて、SSIS 2012 で簡単なパッケージを作成しました。質問で説明したように、TOKEN関数は意図したとおりに動作しません。機能が動作していないように見えることに同意します。この投稿は、元の問題に対する回答ではありません。

比較的簡単な方法で式を記述する別の方法を次に示します。これは、入力レコードの最後のセグメントに常に値がある場合にのみ機能します (たとえば、 A1B2C3など)。

式は次のように書き換えることができます

このステートメントは、入力レコードをパラメーターとして受け取り、区切り文字キャレット (^) を 2 番目のパラメーターとして受け取ります。3 番目のパラメーターは、区切り文字で分割された場合のレコード内の合計セグメント数を計算します。最後のセグメントにデータがある場合、2 つのセグメントがあることが保証されます。次に、1 を減算して、最後から 2 番目のセグメントを取得できます。

(DT_STR,50,1252)TOKEN(OldImportRecord,"^",TOKENCOUNT(OldImportRecord,"^") - 1)

データ フロー タスクを含む単純なパッケージを作成しました。OLE DB ソースがデータを取得し、派生した変換がデータを解析して分割します (下のスクリーンショットを参照)。次に、出力が宛先テーブルに挿入されます。最後のスクリーンショットでソース テーブルと宛先テーブルを確認できます。宛先テーブルには 2 つの列があります。最初の列には、最後から 2 番目のセグメント データと、区切り記号に基づくセグメント数が格納されます (これも正しくありません)。最後のレコードが正しい結果を取得していないことがわかります。最後のレコードに値がなかった場合8、上記の式はインデックスがゼロと評価されるため失敗します。

表現を簡素化するのに役立つことを願っています。

他に連絡がない場合は、この問題をMicrosoft Connect Web サイトに記録することをお勧めします。

テーブルを作成し、スクリプトを入力します

CREATE TABLE [dbo].[SourceTable](
    [OldImportRecord] [varchar](50) NOT NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[DestinationTable](
    [NewImportRecord] [varchar](50) NOT NULL,
    [CaretCount] [int] NOT NULL
) ON [PRIMARY]
GO

INSERT INTO dbo.SourceTable (OldImportRecord) VALUES 
    ('1^Apple^0001^01/01/2010^Anteater^A1'),
    ('2^Banana^0002^03/15/2010^Bear^B2'),
    ('3^Cranberry^0003^4/15/2010^Crow^C3'),
    ('4^^0004^6/15/2010^Duck^D4'),
    ('5^^^^Emu^E5'),
    ('6^^^^Geese^F6'),
    ('^^^^Pheasant^G7'),
    ('8^^^^Sparrow^');
GO

データ フロー タスク内の派生列変換:

派生列の変換

ソース テーブルと宛先テーブルのデータ:

ソースと宛先のテーブル データ

于 2012-10-16T21:12:14.907 に答える
2

TOKEN は隣接する区切り文字をスキップするだけでなく、前後の区切り文字もスキップします。したがって、例を使用して、次のような「良い」フィールドがある場合:

1^リンゴ^0001^01/01/2010^アリクイ^A1

次のように、隣接する先頭の区切り文字を持つものが続きます。

^^^0004^6/15/2010^Duck^

TOKENCOUNT では区切り文字が 2 つしか見つからず、Token1 には 0004、Token2 には 6/15/2010、Token3 には Duck が割り当てられます。

別の種類の交換を使用しました。先頭やトレーニングに役立たない隣接する区切り文字の間にスペースを配置するのではなく、replace を使用して、区切り文字を自分のテキストでは絶対に見つからない文字で囲みました。次の式は私にとってはうまくいきます。言葉足らずですが、その通りです。

(DT_STR,255,1252)REPLACE(TOKEN(REPLACE(OldImportRecord,"^","~^~"),"^",1),"~","")

もちろん、数字の 1 を必要なトークンに置き換え、必要に応じてキャストを調整します。それが役立つことを願っています。

于 2013-04-23T20:47:57.170 に答える