DataViewクラス

並べ替え、フィルタ、検索、編集それにナビゲーションされるDataTableの、データ バインド可能でカスタマイズされたビューを表せます。DataViewのインスタンスはそれのコンストラクタか、DataTableのDefaultViewプロパティから取得できます。並べ替えやフィルタされた結果が必要なだけならば、DataTable.Select()で得られます。

コンストラクタ

DataView dataView = new DataView();
dataView.Table = dataTable;
dataView.Sort = "col1 DESC";      // ソートの基準となる列の名前
dataView.RowFilter = "col2 < 10"; // 行がどのようにフィルタされるかを表す式

パフォーマンスを考慮するならば、ソートやフィルタはコンストラクタで指定します。これをプロパティから設定すると、それらのインデックス (索引) の作成が2度行われることになります。DataView - DataView.cs

public DataView (
    System.Data.DataTable table,
    string RowFilter,
    string Sort,
    System.Data.DataViewRowState RowState
    );
DataView(DataTable, String, String, DataViewRowState) - DataView Constructor (System.Data) | Microsoft Learn

プロパティ

プロパティ 内容
DataTable Table ビューのソースであるDataTable
DataRowView Item[Int32] 指定の行
string Sort 並べ替えに使用する列の名前。既定は空文字列
string RowFilter 表示する行を決めるフィルタに使用する式。既定は空文字列
DataViewRowState RowStateFilter 表示する行を決める行の状態フィルタ。既定はCurrentRows
     
Properties - DataView Class (System.Data) | Microsoft Learn

Item[Int32]

foreach (DataRowView dataRowView in dataView)
{
}

Sort

ソートの基準となる列名に続けて、昇順ならば"ASC"、降順ならば"DESC"を指定します。順を省略すると昇順となります。複数の列を基準とする場合は、それらをコンマで区切ります。DataView.Sort Property (System.Data) | Microsoft Learn

dataView.Sort = "col1";

次の例の場合、col2で降順に並べ替えられたうえで、col1で昇順に並べ替えられます。

dataView.Sort = "col1 ASC, col2 DESC";

並べ替えの規則は、列のDataColumn.DataTypeプロパティの型に基づいて行われます。よってその型が文字列や数値のとき、データがnullの行は昇順では先に、降順では後に表示されます。

int r1 = String.Compare("a", "b");  // -1 ("a" は "b" より前)
int r2 = String.Compare("a", null); //  1 ("a" は null より後)

int n1 = 1.CompareTo(2);    // -1 (1 は 2 より前)
int n2 = 1.CompareTo(null); //  1 (1 は null より後)

RowFilter

表示する行を決めるフィルタで、DataView RowFilter Syntax [C#]にある構文に従って指定します。このフィルタを解除するには、空文字列またはnullを指定します。DataView.RowFilter Property (System.Data) | Microsoft Learn

このRowFilterは、データ バインドしたコントロールにフィルタした結果を表示するために用います。このプロパティは設定する度にインデックスが再構築されるため、パフォーマンスが下がります。特定のクエリの結果を得るのが目的ならば、代わりにFindRows()を呼びます。このメソッドはインデックスの再構築なく実行されます。Find and FindRows - DataView Performance - ADO.NET | Microsoft Learn

dataView.RowFilter = "col1 IN(2,5)";
dataView.RowFilter = "id = 10";      // 特殊文字なし
dataView.RowFilter = "$id = 10";     // 特殊文字なし

列名に特殊文字「~ ( ) # \ / = > < + - * % & | ^ ' " [ ]」が含まれるならば、列名を[]で囲みます。そのとき「] \」を含むならば、それらをさらにバックスラッシュでエスケープします。

dataView.RowFilter = "[#id] = 10";   // "#"が特殊文字
dataView.RowFilter = "[[id\]] = 10"; // "["と"]"が特殊文字。さらに"]"をエスケープ

リテラル

文字列値はシングルクォートで囲みます。もし文字列にシングルクォートが含まれるならば、それを二重にします。

// String values
dataView.RowFilter = "Name = 'John'";       // string value
dataView.RowFilter = "Name = 'John ''A'''"; // string with single quotes "John 'A'"

数値はどの文字でも囲みません。値はインバリアント (invariant) または英語カルチャでのint.ToString()またはfloat.ToString()の結果と同じとします。

// Number values
dataView.RowFilter = "Year = 2008";    // integer value
dataView.RowFilter = "Price = 1199.9"; // float value

dataView.RowFilter = String.Format(CultureInfo.InvariantCulture.NumberFormat,
                     "Price = {0}", 1199.9f);

日時はシャープで囲みます。その書式はインバリアント (invariant) または英語カルチャでのDateTime.ToString()の結果と同じとします。

// Date values
dataView.RowFilter = "Date = #12/31/2008#";          // date value (time is 00:00:00)
dataView.RowFilter = "Date = #2008-12-31#";          // also this format is supported
dataView.RowFilter = "Date = #12/31/2008 16:44:58#"; // date and time value

dataView.RowFilter = String.Format(CultureInfo.InvariantCulture.DateTimeFormat,
                     "Date = #{0}#", new DateTime(2008, 12, 31, 16, 44, 58));

ただしインバリアントなカルチャの書式で取得できるDateTime.ToString(new DateTimeFormatInfo())にはミリ秒単位の情報が含まれないため、その情報を含む行には一致しません。よってISO 8601準拠の書式で取得できるDateTime.ToString("o")を用いるのが確実です。

dataView.RowFilter = $"Date = #{dateTime:o}#";

TimeSpanなどのIConvertibleを実装しない型は、文字列などに変換した上で比較します。c# - DataView RowFilter with TimeSpan DataType - Stack Overflow

dataView.RowFilter = "Time = 10";      // System.Data.EvaluateException「System.TimeSpan および System.Int32 で '=' 操作を実行できません。」
dataView.RowFilter = "Time = 'PT10S'"; // System.Data.EvaluateException「System.TimeSpan および System.String で '=' 操作を実行できません。」
dataView.RowFilter = "Convert(Time, 'System.String') = 'PT10S'";

比較演算子

dataView.RowFilter = "Num = 10";          // number is equal to 10
dataView.RowFilter = "Date < #1/1/2008#"; // date is less than 1/1/2008
dataView.RowFilter = "Name <> 'John'";    // string is not equal to 'John'
dataView.RowFilter = "Name >= 'Jo'";      // string comparison

文字列に対する不等号は、文字列の相対位置で比較されます。

IN演算子
// Operator IN
dataView.RowFilter = "Id IN (1, 2, 3)";                    // integer values
dataView.RowFilter = "Price IN (1.0, 9.9, 11.5)";          // float values
dataView.RowFilter = "Name IN ('John', 'Jim', 'Tom')";     // string values
dataView.RowFilter = "Date IN (#12/31/2008#, #1/1/2009#)"; // date time values

dataView.RowFilter = "Id NOT IN (1, 2, 3)";  // values not from the list

演算子は大文字/小文字が区別されません。これは他の演算子にも該当します。

LIKE演算子

ワイルドカードを使用するには、演算子をLIKEとします。ワイルドカードは「*」または「%」を使用でき、いずれでも意味は同じです。

// Operator LIKE
dataView.RowFilter = "Name LIKE 'j*'";     // values that start with 'j'
dataView.RowFilter = "Name LIKE '%jo%'";   // values that contain 'jo'

dataView.RowFilter = "Name NOT LIKE 'j*'"; // values that don't start with 'j'

パターン文字列に特殊文字「* % [ ]」が含まれるならば、それらを[]で囲みます。

dataView.RowFilter = "Name LIKE '[*]*'"; // values that starts with '*'
dataView.RowFilter = "Name LIKE '[[]*'"; // values that starts with '['
IS演算子

この演算子はNULLとの組み合わせのみ有効で、DBNullに一致します。c# - how to use DataTable.Select() to select Null/ empty values? - Stack Overflow

dataView.RowFilter = "Name IS NULL";
dataView.RowFilter = "Name IS NOT NULL";

ドキュメントにはありませんが、この演算子はSelectクラスなどで用いられています。

ブール演算子

dataView.RowFilter = "City = 'Tokyo' AND (Age < 20 OR Age > 60)";

算術演算子

dataView.RowFilter = "MotherAge - Age < 20"; // people with young mother
dataView.RowFilter = "Age % 10 = 0";         // people with decennial birthday

親子参照関係

親テーブルを対象にフィルタを適用するにはParent.列名、子テーブルならばChild.列名の形式で指定します。また、子の関連は複数の行を返すことがあるため、集合関数 (aggregate function) 内に含めます。DataColumn.Expression Property (System.Data) | Microsoft Learn

dataView.RowFilter = "Sum(Child.col1) < 10";

このときテーブルが複数の子テーブルを持つならば、Child(関連名).列名のように関連名も指定します。

dataView.RowFilter = "Sum(Child(relation1).col2) < 10";
集合関数
   
Sum Sum
Avg Average
Min Minimum
Max Maximum
Count Count
StDev Statistical standard deviation (標準偏差)
Var Statistical variance (分散)
孫テーブル

子テーブルに表示を制御するための列を追加しておき、その列の値が孫テーブルの値で決定されるようにExpressionを指定しておきます。そしてその列を条件に、親テーブルに式を設定します。vb.net - ADO.NET - Accessing Each DataView in DataViewManager - Stack Overflow

DataColumn column = childTable.Columns.Add("visible", typeof(bool));
column.Expression = "IIF(Sum(Child.col1) < 10, 1, 0)";

dataView.RowFilter = "Max(Child.visible) = 1";

または子テーブルでその子テーブルをフィルタし、関連させている列から親テーブルをフィルタする方法もありますが、このような複雑な条件ではLINQを用いた方が効率的です。

DataRow[] childRows = childTable.Select("Sum(Child.col1) < 10");

List<int> ids = new List<int>();
foreach (DataRow row in childRows)
{
    ids.Add(row.Field<int>("id"));
}

dataView.RowFilter = $"id IN ({String.Join(",", ids)})";

もしくはDataView.Tableを子テーブルとして、その結果のDataRowView.Row.GetParentRow()で親テーブルのDataRowを取得します。この方法ならば、階層の深い孫テーブル以下にも適用できます。

LINQ

より複雑な条件でフィルタを適用するには、LINQ to DataSetを用います。たとえばDataViewで、

DataView dataView = new DataView();
dataView.Table = dataTable;
dataView.RowFilter = "col1 > 1";

foreach (DataRowView dataRowView in dataView)
{
    Console.Write(dataRowView["id"]);
}

とする処理は、LINQでは次のようにします。

IEnumerable<DataRow> query =
    from row in dataTable.AsEnumerable()
    where row.Field<int>("col1") > 1
    select row;

foreach (DataRow dataRow in query)
{
    Console.Write(dataRow["id"]);
}

RowStateFilter

下表のDataViewRowStateの組み合わせで指定します。

DataViewRowState 列挙型
列挙子 数値 内容
None 0 None.
Unchanged 2 An unchanged row.
Added 4 A new row.
Deleted 8 A deleted row.
ModifiedCurrent 16 変更された元のデータの、現在のバージョン。ModifiedOriginalを参照

DataRowState.Modified と等値 ModifiedCurrent - DataViewRowState.cs

ModifiedOriginal 32 変更されたデータの、元のバージョン

(Although the data has since been modified, it is available as ModifiedCurrent)

CurrentRows 22 Current rows including unchanged, new, and modified rows. By default, DataViewRowState is set to CurrentRows.

Unchanged | Added | ModifiedCurrent と同等

OriginalRows 42 Original rows including unchanged and deleted rows.

Unchanged | Deleted | ModifiedOriginal と同等

DataViewRowState Enum (System.Data) | Microsoft Learn

メソッド

メソッド 機能
AddNew() ビューに新しい行を追加する
ToTable() 現在のビューに存在する行をもとに、新しいテーブルを作成して返す
Find(Object) 指定の並べ替えキー (sort key) に一致した、最初の行のインデックスを取得できる
FindRows(Object) 指定の並べ替えキー (sort key) に一致した、DataRowViewの配列を取得できる
   
Methods - DataView Class (System.Data) | Microsoft Learn

AddNew()

public virtual System.Data.DataRowView AddNew ();
DataView.AddNew Method (System.Data) | Microsoft Learn

Tableプロパティがnullだと、NullReferenceExceptionが発生し行の追加に失敗します。

FindRows()

Sortで指定されている列でkeyに一致した、DataRowViewの配列を取得できます。

public System.Data.DataRowView[] FindRows (object key);
FindRows(Object) - DataView.FindRows Method (System.Data) | Microsoft Learn

Sortプロパティで並べ替え列を指定していないと、「Find は、並べ替え順序に基づいて行を検索しますが、並べ替え順序が指定されていません。」としてArgumentExceptionが投げられます。

DataTable dataTable = new DataTable();
dataTable.Columns.Add("col1");
dataTable.Columns.Add("col2");

dataTable.Rows.Add("a", "b");
dataTable.Rows.Add("c", "d");

DataView dataView = new DataView(dataTable);
dataView.Sort = "col2";

DataRowView[] found = dataView.FindRows("d");
// found[0].Row.ItemArray "c", "d"
Microsoft Learnから検索