はじめに
この投稿は、RPAツール「UiPath」で Datatable からデータを絞り込む方法について、個人的にまとめたものです。
データテーブルの操作 シリーズ
DataTable の操作方法について記載した記事が、他にもあります。参考まで。
絞り込み方法
UiPath で、データテーブルから条件指定してデータを取得するには、以下の方法があります。
No | 方法 | 評価 | コメント |
---|---|---|---|
1 | 「データ テーブルをフィルター」 アクティビティを使用 |
UiPath では一般的 | SelectやLinqの方が見やすい 比較時に型変換(型揃え)が出来ない |
2 | Datatableの「.Select」メソッドを使用 | VB では一般的 | 比較時に型変換(型揃え)が出来る 列の加工・削除ができない |
3 | 「LINQ to Object(メソッド構文)」 を使用 | .NET では一般的 (少し難しい) |
基本何でもできる 横に長くなりがち |
4 | 「LINQ to SQL(クエリ式)」 を使用 | .NET では一般的 (少し難しい) |
基本何でもできる 縦横に長くなりがち |
以下で、説明していきます。
1)データ テーブルをフィルター アクティビティ
標準アクティビティで提供されている「データ テーブルをフィルター」アクティビティで、絞り込みが出来ます。機能的には十分です。
「フィルタを指定」ボタンを押すと、ウィザードが表示され、条件を設定します。複数の条件の指定も可能で、絞り込み後に「残す/削除する」列の指定も可能です。
残念な点としては「フィルタを指定」ボタンを押さないと、フロー上での絞り込み内容が見れません
。(ボタンを押さないでも見えるようになってほしい)
また、データの型が「DateTime型」等の「書式によっては値比較が正確にできない」ものは、絞り込みができない事があります。
(値の比較時に、右辺左辺の型変換ができない)
(上記のように「厳格に型を意識する必要がない」場合)基本的には、このアクティビティで絞り込みをすれば良いのですが、「処理が遅い」
場合あります。
また「少し凝った操作をしたい
」場合は、以下で紹介する「Selectメソッド」か「LINQ」で操作することになります。
要するに「標準アクティビティでは出来ない」ことがあり、その場合「Selectメソッド」か「LINQ」で操作する必要があるということです。
(アクティビティに欲しい機能の追加がされるまでは・・・。)
また、類似アクティビティで「データ テーブルを検索」アクティビティがありますが、検索結果と合致した行番号しか取れないので、絞り込むには少し機能が足りません。
2)Datatableの「.Select」メソッド
Datatable が提供する Select メソッドを使用して、DataRow オブジェクトの配列を取得できます。
Select メソッドには、4種類の指定方法があります。
No | メソッドの指定 | 内容 |
---|---|---|
1 | .Select() | すべての 行を取得 ※稀に使う(ほぼ使わない) |
2 | .Select("絞込条件") | 絞込条件に合致する 行を取得 |
3 | .Select("絞込条件", "並替指定") | 絞込条件に合致する 行を 並替して取得 |
4 | .Select("絞込条件", "並替指定", "行の状態指定") | 絞込条件と行状態指定に合致する 行を 並替して取得 ※UiPathでは使うことは無い |
以下のような式を、代入アクティビティ等にセットして使用します。
'// .Select("絞込条件") のサンプル
dt.Select("id='A001'") '// IDが「A001」
dt.Select("width>20 AND height=10") '// 幅が20より大きく、高さが10
dt.Select("width>20 OR height=10") '// 幅が20より大きい、または、高さが10
'// .Select("絞込条件", "並替指定")) のサンプル
dt.Select("width>20", "width ASC") '// 幅の昇順で、幅が20より大きい
dt.Select("width>20", "width DESC") '// 幅の降順で、幅が20より大きい
dt.Select("width>20", "width, height DESC") '// 幅の昇順・高さの昇順で、幅が20より大
SELECTで、複数列指定で絞り込みをする場合、データ件数によっては処理が遅くなります。
列の指定を 2 回以上に分けて、SELECTで絞り込むと改善します。
配列/DataRow ではなく DataTable で取得したい場合は、後ろに「.CopyToDataTable」を付けます。
dt.Select("width>20", "width, height DESC").CopyToDataTable
ですが、絞り込み結果が0件の場合に「DataRow が含まれていません」エラーになります。「CopyToDataTable」を実行するためには、必ずデータ1件以上必要なためです。
これを回避するには、一度「配列型」に格納したあとで「配列の件数が0で無い」場合に「CopyToDataTable」するようにします。
'// 件数は悪用の変数を用意
enum_row As IEnumerable<DataRow>
'// 代入1回目(件数把握)
enum_row = dt.Select("id='A001'")
'// 代入2回目(データが0件なら、空のDataTableをセット)
dt = If(enum_row.Count = 0, dt.Clone, enum_row.CopyToDataTable)
System.Collections.Generic.IEnumerable
3)LINQ to Object(メソッド構文)
LINQ to Object は、繰り返し型(IEnumerableインターフェース)のオブジェクトに対して、一括で処理する方法です。以下のように「 . 」で繋ぎながら、配列操作します。
'// region が tokyo のデータを取得
dt.AsEnumerable().Where(function(r) r("region").ToString.ToLower = "tokyo")
'// region が t で始まるデータを age が低い順 で取得
dt.AsEnumerable().Where(function(r) r("region").ToString.ToLower.StartsWith("t")
).OrderBy(function(r) r("age"))
'// region が Tokyo で age が 31以上 のデータを age が高い順 で取得
dt.AsEnumerable().Where(function(r) r("region").ToString = "Tokyo" _
AndAlso CType(r("age"), Int32) > 30
).OrderByDescending(function(r) r("age"))
'// region が Tokyo または Osaka のデータを age の高い順、名前順 で取得
dt.AsEnumerable().Where(function(r) r("region").ToString = "Tokyo" _
OrElse r("region").ToString = "Osaka"
).OrderByDescending(function(r) r("age")
).ThenBy(function(r) r("name"))
. の後ろは Linq拡張メソッド で、指定できるものがいくつかあります。以下は比較的よく使います。
種類 | メソッド | 戻り値 |
---|---|---|
絞り込み | Where | 条件を満たすデータ |
並び替え | OrderBy | 昇順データ |
並び替え | OrderByDescending | 降順データ |
並び替え | ThenBy | 昇順データ(2回目以降の並び替え) |
並び替え | ThenByDescending | 降順データ(2回目以降の並び替え) |
選択/射影 | Select | 指定した要素 |
集計 | Max | 最大値 |
集計 | Min | 最小値 |
集計 | Sum | 合計値 |
集計 | Average | 平均値 |
集計 | Count | 合致数 |
判定 | All | すべて が条件を満たすか |
判定 | Any | いずれか が条件を満たすか |
判定 | Contains | 含むか |
要素取得 | FirstOrDefault | 1件目または初期値 |
取得結果を、列配列ではなく DataTable で取得したい場合は、後ろに「.CopyToDataTable」を付けます。
'// region が Tokyo のデータを取得
dt.AsEnumerable().Where(function(r) r("region").ToString = "tokyo").CopyToDataTable
横に長くなるため、フローの可読性は落ちます。区切りのいい位置で、改行を挟む等の工夫が必要です。
「.Where・・・」のようにドットが先頭になると構文エラーになるので注意が必要です。
アンダースコア(_)を最後に書くと、エラーを回避できます。
4)LINQ to SQL(クエリ式)
LINQ to SQL は SQLクエリのようにデータを絞り込む方法です。「SELECT・FROM・WHERE」などの式を使用します。
SQLクエリとの比較で言うと、以下のようになります。
SQL式 | LINQ式 |
---|---|
SELECT | select |
FROM | from in |
WHERE | where |
ORDER BY | orderby |
GROUP BY | group by into |
書き方の順ですが、LINQ式の場合、SELECT は後ろ(Orderbyの前)に来ます。
'// region が Tokyo のデータを取得
From r In dt.AsEnumerable()
Select r
Where r("region").ToString = "tokyo"
'// age が高い順 で取得
From r In dt.AsEnumerable()
Select r
Order By r.Field(Of Integer)("age") Descending
'// region が Tokyo で age が 31以上 のデータを age が高い順 で取得
From r In dt.AsEnumerable()
Where r("region").ToString = "Tokyo" AndAlso r.Field(Of Integer)("age") > 30
Select r
Order By r.Field(Of Integer)("age") Descending
'// region が Tokyo または Osaka のデータを age の高い順、名前順 で取得
From r In dt.AsEnumerable()
Where r("region").ToString = "Tokyo" OrElse r("region").ToString = "Osaka"
Select r
order by r.Field(Of Integer)("age") Descending, r("name")
クエリ構文は「遅延バインディング」という仕組みを使用するため「型の明確化」が必要で、列の型「Of XXX」を指定しています。
横に長くなるため、フローの可読性は落ちます。改行を挟む等の工夫が必要です。
終わりに
いかがでしたでしょうか。なにかの役に立てば幸いです。
この記事が参考になったら、 LGTMをお願いします。閲覧ありがとうございました。