4

私は大量のデータの定期的な (毎月の) インポートに取り組んでいます。変換中に、文字列を複数の列に分割していますが、単純な分割ではありません。文字列のどの部分がどのフィールドに入るかを決定するロジックが少しあります。

文字列を複数の部分に分割し、指定されたインデックスの値を提供するインライン関数を作成しました。

パラメータは次のとおりです。

  1. 文字列値
  2. デリミタ
  3. 索引

例えば:

文字列値がX4-728Z5-121-84gffであり、関数で 121 を取得したい場合は、次のように関数を呼び出します。

fn_MyFunc('X4-728Z5-121-84gff', '-', 3)

私の問題はこれです:

私のインポート クエリでは、特定のフィールド値に必要なインデックスは、別のインデックスの値に依存しています。インデックス 1 の値 = の場合はX4インデックス 3、それ以外の場合はインデックス 4 が必要です。

1 つのクエリで、いくつかの case ステートメントの結果に応じて、この関数を 4 回または 5 回呼び出します。

関数は基本的に同じことを何度も繰り返しています...しかし、毎回異なるインデックスを取得しています。文字列を分割するという大変な作業を 1 回だけ行い、同じクエリで異なるインデックスを簡単に取得できるようにするには、どうすれば労力を削減できますか?

これは外部ソースからのデータのインポート中であり、正規化やインデックス付きビューなどを示唆する回答は役に立たないことに注意してください。

編集

私は私の質問を投稿するように頼まれました:

SELECT
    ComplexString,
    CAST(fn_MyFunc(ComplexString, '-', 1) AS NVARCHAR(2)) AS LocationCode,
    CAST(fn_MyFunc(ComplexString, '-', 2) AS NVARCHAR(25)) AS CompanyCode,
    NULLIF(CASE
        WHEN fn_MyFunc(ComplexString, '-', 1) = 'R1' THEN NULL
        ELSE CAST(fn_MyFunc(ComplexString, '-', 3) AS INT)
    END, 0) AS ManagementType,
    CASE
        WHEN fn_MyFunc(ComplexString, '-', 1) = 'R1' THEN CAST(fn_MyFunc(ComplexString, '-', 3) AS VARCHAR(25))
        ELSE CAST(fn_MyFunc(ComplexString, '-', 4) AS NVARCHAR(25))
    END AS Network,
    .
    .
    .
FROM MyTable
4

4 に答える 4

4

すべての文字列の最大値が 4 つの部分である場合、関数の代わりにインラインでこれを実行できます。

SELECT PARSENAME(REPLACE(column, '-', '.'), 
  CASE WHEN (condition for 4th element) THEN 1 
       WHEN (condition for 3rd element) THEN 2
       WHEN (condition for 2nd element) THEN 3
       WHEN (condition for 1st element) THEN 4
   END
FROM ...

次のことも検討できます。

(a) 文字列の各部分を個別の計算列に格納します。計算列を永続化/インデックス化することもできます。

(b) 文字列の個々の部分を最初に別々に格納する - 連結は常に分割よりも簡単です。

更新されたクエリを指定して編集

;WITH x AS
(
  SELECT ComplexString,
         p1 = LEFT(ComplexString, 2),
         p2 = dbo.fn_MyFunc(ComplexString, '-', 2),
         p3 = dbo.fn_MyFunc(ComplexString, '-', 3),    
         p4 = dbo.fn_MyFunc(ComplexString, '-', 4)
         -- , other columns
  FROM dbo.MyTable
)
SELECT
    ComplexString,
    p1 AS LocationCode,
    LEFT(p2, 25) AS CompanyCode,
    CASE WHEN p1 <> 'RI' THEN CONVERT(INT, LEFT(p3, 3)) ELSE 0 END 
      AS ManagementType,
    LEFT(CASE WHEN p1 = 'RI' THEN p3 ELSE p4 END, 25) AS Network
FROM x;
于 2012-06-02T16:48:17.320 に答える
4

文字列を列に分割する分割関数を作成し、cross apply.

5 つの列に分割する関数は次のようになります。

alter function [dbo].[SplitString]
(
    @Value nvarchar(max),
    @Delim nchar(1)
)
returns table as return
(
    select substring(T.Value, 1, T1.P - 1) as C1,
           substring(T.Value, T1.P + 1, T2.P - T1.P - 1) as C2,
           substring(T.Value, T2.P + 1, T3.P - T2.P - 1) as C3,
           substring(T.Value, T3.P + 1, T4.P - T3.P - 1) as C4,
           substring(T.Value, T4.P + 1, T5.P - T4.P - 1) as C5
    from (select @Value+replicate(@Delim, 5)) as T(Value) 
      cross apply (select charindex(@Delim, T.Value)) as T1(P)
      cross apply (select charindex(@Delim, T.Value, T1.P + 1)) as T2(P)
      cross apply (select charindex(@Delim, T.Value, T2.P + 1)) as T3(P)
      cross apply (select charindex(@Delim, T.Value, T3.P + 1)) as T4(P)
      cross apply (select charindex(@Delim, T.Value, T4.P + 1)) as T5(P)
)

そして、それはこのように使用されます。

select *
from YourTable as Y
  cross apply dbo.SplitString(Y.ColumnToSplit, '-') as S

C1, C2, C3, ...この関数は行ごとに 1 回呼び出され、split 関数を新たに呼び出すことなく、フィールド リストまたは where 句の列を使用できます。

于 2012-06-02T17:29:23.857 に答える
0

文字列に固定(または明確な最大)数のパーツがある場合は、@ part1、@ part2などの変数のセットを作成できます(各パーツに特定の意味がある場合は、より適切な名前を使用します)。関数を使用して変数を1回入力し、再解析する代わりに変数を使用します。

- また -

varchar解析方法を使用して、文字列を1つの列と1つのID列を持つ狭い一時テーブルまたはテーブル変数に変換しますtinyint(このトピックに関するSOに関する投稿は多数あります。これ は、csvを対象とした素晴らしい記事ですが、簡単です。あなたの状況に適応可能)。次に、のシーケンス列を使用して、select必要な文字列部分を見つけることができます。

于 2012-06-02T17:15:10.383 に答える
0

文字列の個々の部分がデータに対して実行する操作の中心である場合、オプションとして、部分を個々の列として、または関連するテーブルに保存することで、さらに正規化することができます。

または、個々のパーツを返すテーブル値関数を使用すると、パーツに何度もアクセスする必要がある場合にパフォーマンスを向上させることができます。

于 2012-06-02T16:39:44.360 に答える