カテゴリー
Software Tech

[C#備忘録]2つのDataTableを紐づける | AmpiTa Project

 2つのデータベースには共通項があり、紐づけたいということがあります。

 例えば、片方は個人情報を含む名簿、片方は匿名化された利用履歴のようなもの。利用履歴には年齢や性別が載っていない場合、それらの属性での分析ができません。
 2つのデータベースに共通鍵を設けておき、紐づけることで1つのデータベースとして取り扱うことができます。




  1. OriginalとAddition
  2. 1つのデータベースに2つのテーブル
  3. カラム名
  4. 1つずつ紐づけ
  5. データ追記




OriginalとAddition

 早速、つくってみました。

 元となるデータベースをOriginal、付加情報として用いるデータベースをAdditionとして試作しています。

/*/ データテーブル格納 /*/
DataSet dataSet_Coupling = new DataSet();
dataSet_Coupling.Tables.Add(dataTable_Addition.Copy());
dataSet_Coupling.Tables[dataSet_Coupling.Tables.Count - 1].TableName = "dt_Addition";
int_Col_Addition_Count = dataSet_Coupling.Tables["dt_Addition"].Columns.Count;
dataSet_Coupling.Tables.Add(dataTable_Original.Copy());
dataSet_Coupling.Tables[dataSet_Coupling.Tables.Count - 1].TableName = "dt_Original";
int_Col_Original_Count = dataSet_Coupling.Tables["dt_Original"].Columns.Count;

/*/ カラム設定(重複回避) /*/
for (int_CoNum = 0; int_CoNum < int_Col_Addition_Count; int_CoNum ++)
{
    dataSet_Coupling.Tables["dt_Original"].Columns.Add("追加_" + dataSet_Coupling.Tables["dt_Addition"].Columns[CoNum].ColumnName);
}

/*/ データ接続用DataRow /*/
DataRow[] dtRow_Child_Row;
dataSet_Coupling.Relations.Add(
    "DB_RelationName", 
    dataSet_Coupling.Tables["dt_Original"].Columns["ID_Y"], 
    dataSet_Coupling.Tables["dt_Addition"].Columns["ID_Z"],
    false);
/*/  受け側(Original)のレコードの分だけループ  /*/
foreach (DataRow dataRow_Row in dataSet_Coupling.Tables["dt_Original"].Rows)
{
    dtRow_Child_Row = dataRow_Row.GetChildRows("DB_RelationName");
    if (dtRow_Child_Row.Length != 0)
    {
        for (int_CoNum = 0; int_CoNum  < int_Col_Addition_Count; int_Col_Number++)
        {
            dataSet_Coupling.Tables["dt_Original"].Rows[int_Record_Count][int_CoNum + int_Col_Original_Count] = dtRow_Child_Row[0][int_CoNum ].ToString(); 
        }
    }
    int_Record_Count++;
}
dataSet_Coupling.WriteXmlSchema(str_XSD_File_Name);
dataSet_Coupling.WriteXml(str_XML_File_Name);




1つのデータベースに2つのテーブル

 今回は『dataSet_Coupling』というデータセット(DataSet)に、2つのテーブルを設けました。

 1つ目は『0』(ゼロ)、2つ目は『1』(ワン)ですが、それだとわかりづらいので『dt_Addition』と『dt_Original』というテーブル名(TableName)を付けています。

 追加する側の dt_Addition を先に設定した理由は、2つが同じテーブル名(TableName)であった場合、受け側のテーブル名を温存したいためです。2つ同じテーブル名は許容されないので、先に追加する側を登録してテーブル名を dt_Addition に変更しています。すなわち、 dt_Original というテーブル名にせず、元のままにしても大丈夫です。

 テーブルに追加(Add)の指示をして、コピー(Copy)でデータテーブルを丸ごとコピーしています。
 2回のコピーで、2つのデータテーブルがデータセット内に存在することになります。

/*/ データテーブル格納 /*/
DataSet dataSet_Coupling = new DataSet();
dataSet_Coupling.Tables.Add(dataTable_Addition.Copy());
dataSet_Coupling.Tables[dataSet_Coupling.Tables.Count - 1].TableName = "dt_Addition";
int_Col_Addition_Count = dataSet_Coupling.Tables["dt_Addition"].Columns.Count;
dataSet_Coupling.Tables.Add(dataTable_Original.Copy());
dataSet_Coupling.Tables[dataSet_Coupling.Tables.Count - 1].TableName = "dt_Addition";
int_Col_Original_Count = dataSet_Coupling.Tables["dt_Original"].Columns.Count;




カラム名

 受け側のデータテーブル『dt_Original』には、まだ元となるデータテーブルのデータがコピーされただけです。

 ここに、新しいカラムを追加します。

 今回は、追加する側のテーブルからすべて引き継ぐコードを作ったので、 for 文でカラムを追加しています。

 受け側のカラム名と重複しないように、頭に『追加_』という文字を付けています。これは『SUB』でも『補』でも何でも良いです。

/*/ カラム設定(重複回避) /*/
for (int_CoNum = 0; int_CoNum < int_Col_Addition_Count; int_CoNum ++)
{
    dataSet_Coupling.Tables["dt_Original"].Columns.Add("追加_" + dataSet_Coupling.Tables["dt_Addition"].Columns[CoNum].ColumnName);
}




1つずつ紐づけ

 データセットのリレーション(Relations)を使って2つのデータベースを紐づけます。

 リレーション名は何でも良いです。今回は『DB_RelationName』にしています。

 第2項目は受け側のデータベースです。
 第3項目は追加する側のデータベースです。

 それぞれ、どのカラムの内容で紐づけるか決めます。今回は『ID_Y』と『ID_Z』が共通鍵になっていることにして、この2つをキーにしています。
 主キー、プライマリキー、ユニークキー、リレーショナルキー、なんと呼ぶのが良いかわかりません。

/*/ データ接続用DataRow /*/
DataRow[] dtRow_Child_Row;
dataSet_Coupling.Relations.Add(
    "DB_RelationName", 
    dataSet_Coupling.Tables["dt_Original"].Columns["ID_Y"], 
    dataSet_Coupling.Tables["dt_Addition"].Columns["ID_Z"],
    false);




データ追記

 受け側のデータテーブルには、カラムは新設されましたがデータが格納されていません。

 受け側のデータテーブルを1レコードずつ、最初から最後まで foreach を使って追記していきます。

 追加する側の dt_Addition の項目が空欄である場合、あるいは紐づくレコードが存在しない場合は、受け側のデータテーブルには空欄(Null)が記録されます。

/*/  受け側(Original)のレコードの分だけループ  /*/
foreach (DataRow dataRow_Row in dataSet_Coupling.Tables["dt_Original"].Rows)
{
    dtRow_Child_Row = dataRow_Row.GetChildRows("DB_RelationName");
    if (dtRow_Child_Row.Length != 0)
    {
        for (int_CoNum = 0; int_CoNum  < int_Col_Addition_Count; int_Col_Number++)
        {
            dataSet_Coupling.Tables["dt_Original"].Rows[int_Record_Count][int_CoNum + int_Col_Original_Count] = dtRow_Child_Row[0][int_CoNum ].ToString(); 
        }
    }
    int_Record_Count++;
}
dataSet_Coupling.WriteXmlSchema(str_XSD_File_Name);
dataSet_Coupling.WriteXml(str_XML_File_Name);




おわりに

 今回は、2つのでデータテーブルを結合させる処理を実装しました。

 以前、植え込み型の医療機器の管理システムを構築した際に使った技術ですが、すっかり忘れていました。

 受け側のデータテーブルは保留し、追加する側のデータテーブルを次々と用意していけば、一度の処理でいくつものデータを追加していくことも可能です。以前は患者テーブル、病院テーブル、保険テーブルなどいろいろなものを持ったデータベースでしたので、もっと複雑でした。

 システムの終了時に、データテーブルを抹消するコードを入れておけば、個人情報流出も防げるかなと思います。

 最後までお読みいただき、ありがとうございました。




関連記事