web-dev-qa-db-ja.com

ヘッダーレコードに基づくデータのグループ化

未加工のSQL Server 2016データベースであるデータベースにインポートするスプレッドシートがあります。銀行が明らかに使用している「ロックボックス形式」と呼ばれる形式のレコードがあります。一般的には次のようになります。

Batch1の詳細
子レコード
別の子レコード
バッチの概要
Batch2のヘッダー行

ここにフィドルを設定しています

注意すべき重要な点は次のとおりです。

  • 列1は、行のレコードの「タイプ」を示します。唯一の「ユニバーサル」列です。
  • 他のすべての列は、レコードのタイプに基づいて本質的に変化します。
  • 子レコードを親に関連付ける唯一のことは、子レコードが親の後で、次の親の前に表示されることです。 IDは行間で共有されません。
  • バッチに続く子行の数は可変です(予測不可能)。

これをクエリして簡単にグループ化できる方法はありますか?バッチとその子+フッターレコードですか?私がしなければならないことの1つは、フッターレコードに適切な集計が含まれていることを示すことです(子レコードから取得されます。確認する必要があるものの一部であるバッチの子レコードの数を含みます)。

5
peacedog

入力データの順序が、バッチの開始(Column1=1)は常にそのバッチ内で最小のRowNumberを持っています。次のようにして、先行するヘッダーレコードの中で最大のRowNumberを使用して疑似バッチ番号を割り当てることができます。

select t.*, 
    max(case column1 when 1 then RowNumber end) 
    over(order by rownumber range between unbounded preceding and current row) as batchid
from tbl t  

フィドル

そこから、サブセレクトで上記をラップし、疑似バッチ番号を使用してデータを分割したりデータをグループ化したりすると、集計関数またはウィンドウ関数を使用して集計を計算できます。

select 
max(case column1 when 1 then column3 end) as batchid,
sum(case column1 when 2 then some_numeric_column end) as sum_children,
max(case column1 when 8 then column3 end) as footer_value
from (
  select t.*, 
    max(case column1 when 1 then rownumber end) 
    over(order by rownumber range between unbounded preceding and current row) as batchnum
from tbl
) t1
group by batchnum
1
mustaccio

ファイル内のレコードの意味は、本質的にレコードのシーケンスに依存します。ただし、リレーショナルデータベースでは、テーブル内の行のシーケンスは保証されません。したがって、ファイルをテーブルにロードするとすぐに、重要な情報が失われます。

さらに、テーブル内の行には同じ列が必要です。ファイルの各レコードは異なるフィールドを持つことができるため、2つは固有のものです。

[〜#〜] bulk [〜#〜] オプションとともに [〜#〜] openrowset [〜#〜] を使用すると、順序を維持できます。ドキュメントでは、ソースの順序が保持されることを明示的に述べていませんが、FIRSTROWとLASTROWを指定できるため、影響が強くなります。これにより、 identity または sequence をデータまたはカーソルに挿入できるため、後の処理でソースの順序を再現できます。

2番目の制限を回避するには、適切なテーブル設計をいくらか覆し、列を実行時に意味が定義されているBLOBとして処理します。これにより、これらの列が文字型で定義され、その後T-SQLで文字列操作が行われます。

より良いアプローチは、プログラミング言語でファイルを前処理し、バッチが正しく解釈された後でのみSQL Serverに書き込むことです。 PHBがT-SQLソリューションを主張する必要がある場合は、SQL CLRを検討してください。

1
Michael Green