カテゴリー
Software Tech

[C#備忘録]XML・DataTable絞込・指示 | AmpiTa Project

 データベースを扱っている上で基本となるDataTable(データテーブル)の取扱いですが、データの絞込や指示について手順を忘れていることが多いので、次回のために備忘録を作成しています。




大量のデータも軽量で扱えるDataTable

 少量のデータであれば変数を使って取り扱うことができます。

 例えばDataGridViewのカラム数分のデータであれば下記のように『int[]』でカラム数分の変数を発生させ、そこに格納していくことで対応できます。

int[] intColumns = new int[dataGridView.Columns.Count];

 1行、1次元であればこれで済みますが、それが1,000行分となると2次元的にデータを扱うことになり、しかも1,000行×20列などとなれば20,000個も変数を扱うことになり、管理する側も頭が追いつきません。

 そこで、データテーブルを使います。

 データテーブルの宣言は1行でできます。

DataTable dtTbl_Viewer = new DataTable();




ExcelもDataTable化

 Excelも読取だけであれば簡単にデータテーブルを作る事ができます。

 下記コードはExcelをデータテーブル化して、シート数と1個目(0番)のシート名を取得しているコードです。

using (FileStream filestream_Excel = System.IO.File.Open(@var_Excel_File_Path, FileMode.Open, FileAccess.Read))
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(filestream_Excel))
{
  var ds_Data_Set_Excel = excelReader.AsDataSet(); 
  int int_SheetCount = ds_Data_Set_Excel.Tables.Count;
  string str_SheetName = ds_Data_Set_Excel.Tables[0].TableName
  if (filestream_Excel != null) { filestream_Excel.Close(); } }
}

 これの取扱いは別の記事をご参照ください。




絞込

 データを在る条件で絞り込もうというときは『Select』を使います。

 仮に『dtTbl_Viewer』というデータテーブルがあり、データグリッドビューで表示していたとします。このデータテーブルの3列目(列番号2)が都道府県であったとして、その列が『兵庫県』のデータだけを表示したかったとします。

 その場合、『Select』の中に記述する絞込の構文は『[都道府県] =’兵庫県’』となります。

 下記コードではカラム名『都道府県』は文字で指定ではなく引用しています。『dtTbl_Viewer』のカラム番号『2』のカラム名(ColumnName)を文字列(ToString)で取得して条件文に入れます。
 カラム名の前後にある『[ ]』ですが、これは省略可能です。ただし、カラム名に『%』などの記号が入っていた場合、条件設定としての『%』と識別できないためカラム名の途中から絞込条件が作られてしまいます。無難なのは括弧を入れて置くことです。

DataTable dtTbl_Reference = new DataTable();
string str_Search = "[" + dtTbl_Viewer.Columns[2].ColumnName.ToString() + "]" + "='" + "兵庫県" + "'";
if (dtTbl_Viewer.Select(str_Search ).Count() > 0) 
{
  dtTbl_Reference = dtTbl_Viewer.Select(str_Search ).CopyToDataTable();
  dtTbl_Reference.TableName = str_Search .TableName;
}

 このコードでは『if』でレコードが1つ以上あること(0超過)を確認しています。ゼロの場合、色々と不都合があるためです。セレクト(Select)構文では後ろにカウント(Count)を付ければ行数(レコード数)を取得できます。

dtTbl_Viewer.Select(str_Search ).Count() > 0

 問題なければ『CopyToDataTable』で丸ごとコピーします。

dtTbl_Viewer.Select(str_Search ).CopyToDataTable();

 この丸写し処理でもコピーされないのがテーブル名です。なぜかわかりませんし、テーブル名を使わない場合は問題ないと思いますが、筆者のプログラムではテーブル名を識別して処理するコードがあるため明示的に下記コードを入れています。

dtTbl_Reference.TableName = str_Search .TableName;




DataGridViewの行指示(行選択)

 絞込の場合、指定した条件に合致するデータ以外は消えてしまいます。

 全件表示したままで、目的のデータを見つけ出す方法として、以下の方法があります。

 一行ずつセルをチェックしていく方法です。

 非常に姑息的ですが。

intC = dataGridView.RowCount;
if (long.TryParse(txbS.Text, out long longS))
{
    for (intR = intF; intR < intC; intR++) 
    {
        if (long.TryParse (dataGridView.Rows[intR].Cells[intC].Value.ToString(), out longR))
        {
            if (longR >= longS) 
            {
                break; 
            }
        }
    }
}

 『intF』は前回の指示での終わり値です。初出の場合はゼロになるようにします。前回の続きからという場合は、前回の値を引き継ぎます。

 『intC』は総カラム数です。

 『intR』は現在の行番号を示す変数です。for構文で使います。

 『longS』は検索の基準とする数値です。テキストボックスに入力した文字を数値変換しています。
 数値しか扱わないのであればテキストボックスを数値限定にすることもできますが、文字や日付など色々と扱う場合にはTryParseで変換します。

 for構文ではデータグリッドビューを1行ずつ確認していきます。

 データグリッドビューのセルを1つずつ、数値変換(long.TryParse)で数値化し、longSと比較します。

 今回は以上『>=』にしていますが、この記号は任意に変更できます。

intC = dataGridView.RowCount;
strWord = "Osaka"
for (intR = 0; intR < intC; intR++) 
{
    if (dataGridView.Rows[intR ].Cells[4].Value.ToString() == strWord)
    {
        dataGridView.CurrentCell = dataGridView.Rows[intR].Cells[7];
        break;
    }
}

 上記は、DataGridViewを1行目から末端まで巡回してヒットさせるものです。

 5列目のセル(セル番号4)に格納されている文字列が『Osaka』であった場合にヒットしたことになります。

 ヒットした行で、左から8列目のセル(セル番号7)をハイライトする指示をだして for 句から抜けます。




条件を複雑化

 下のコードは、データ型が文字列(String)か、整数型(Int)か、小数型(Double)かで探し方を変えるコードです。

 データは『一致』(==)だけでなく、文字列であれば『含む』や『不一致』などを選択、数値であれば『以上』『未満』などを選択できるようにしています。
 この場合分けはコンボボックス『cmb_Src』というもので実施しています。cmb_Srcの表示テキストで仕分けしていますが SelectedIndex で処理した方がスマートかもしれません。

 数値の場合、入力ワードが数値であるかどうかの判定をコードを実行してから全行検索するようにしています。
 もし、数値でなかった場合には、その先には進まず離脱します。実際にはここでエラーメッセージを出すようにしています。

 『intN』はカラム番号です。どのカラムを選択して検索するか定義します。
 『intDs』『doubleDs』は比較用の基準データ、『intDr』『doubleDr』は現在の対象データです。

if(dtTbl_Reference.Columns[intN].DataType == typeof(int)
{
    if (int.TryParse(strWord, out intDs) {}
    else { return; }
}
else if(dtTbl_Reference.Columns[intN].DataType == typeof(double)
{
    if (double.TryParse(strWord, out doubleDs) {}
    else { return; }
}

for (intR = intF; intR < intC; intR++)
{
    dataGridView.CurrentCell = dataGridView.Rows[intR].Cells[intN];
    if(dtTbl_Reference.Columns[intN].DataType == typeof(string)
    {
        if (cmb_Src.Text == "一致")
        {
            if (dataGridView.CurrentCell.Value.ToString() == strWord)
            {
                return;
            }
        }
        else if (cmb_Src.Text == "含む")
        {
            if (dataGridView.CurrentCell.Value.ToString().Contains(strWord))
            {
                return;
            }
        }
    }
    else if(dtTbl_Reference.Columns[intN].DataType == typeof(int)
    {
        if (int.TryParse(strWord, out intDr)
        {
            if (cmb_Src.Text == "一致")
            {
                if (intDr == intDs)
                {
                    return;
                }
            }
            else if (cmb_Src.Text == "以上")
            {
                if (intDr >= intDs)
                {
                    return;
                }
            }
            else if (cmb_Src.Text == "以下")
            {
                if (intDr <= intDs)
                {
                    return;
                }
            }
        }
    }
    else if(dtTbl_Reference.Columns[intN].DataType == typeof(double)
    {
        if (int.TryParse(strWord, out doubleDr)
        {
            if (cmb_Src.Text == "一致")
            {
                if (doubleDr == doubleDs)
                {
                    return;
                }
            }
            else if (cmb_Src.Text == "以上")
            {
                if (doubleDr >= doubleDs)
                {
                    return;
                }
            }
            else if (cmb_Src.Text == "以下")
            {
                if (doubleDr <= doubleDs)
                {
                    return;
                }
            }
        }
    }
}




おわりに

 今回は絞込や指示についての備忘録でした。

 特に『Select』構文で項目名に『[ ]』を付けることで思わぬエラーを回避できたことをメモしておきました。




関連記事

「[C#備忘録]XML・DataTable絞込・指示 | AmpiTa Project」への1件の返信