読者です 読者をやめる 読者になる 読者になる

いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

ADO.NET入門記-018 (DataViewを用いた重複行の取り除き)(DataTable, DataView, ToTable, distinct)

C# ADO.NET


データを扱っていると、たまに処理上重複データを取り除いたりする必要があったります。
SQLでデータを取得する場合は、事前にdistinctするなどできますが、内部で作成したデータの
場合はそうもいきません。


そんな時、DataViewを使うと楽な場合があります。
以下のメソッドを利用すると重複行を取り除いた新たなデータテーブルを返してくれます。

DataView.ToTable(string, bool, string[])

第二引数にtrueを渡すと、重複行が取り除かれます。


てことで、以下、サンプルです。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Windows.Forms;

namespace Gsf.Demo{

    public class DemoForm : Form{

        Button        btnDoFilter;
        Button        btnDoDistinct;
        DataGridView  grdMain;

        DataTable     _table;
        DataView      _view;
        BindingSource _dataSource;

        public DemoForm(){
            InitializeComponent();
            InitializeControlData();
            InitializeEventSettings();
            InitializeDataBindings();
        }

        protected void InitializeComponent(){
            SuspendLayout();

            Text          = "DataView Sample";
            Size          = new Size(600, 400);
            StartPosition = FormStartPosition.CenterScreen;

            btnDoFilter = new Button();
            btnDoFilter.Text     = "Do Filter";
            btnDoFilter.Location = new Point(0, 0);

            btnDoDistinct = new Button();
            btnDoDistinct.Text     = "Do Distinct";
            btnDoDistinct.Location = new Point*1;

            Controls.AddRange(new Control{btnDoFilter, btnDoDistinct, grdMain});

            ResumeLayout();
        }

        protected void InitializeControlData(){

            _table      = new DataTable("SAMPLE_DATA");

            _table.Columns.Add("ID",  typeof(int));
            _table.Columns.Add("NAME");
            _table.Columns.Add("AGE", typeof(int));

            DataRow newRow = null;
            for(int i = 0; i < 1000; i++){
                newRow = _table.NewRow();
                newRow.ItemArray = 
                    new object{
                        i,
                        string.Format("gsf_zero{0}", i),
                        (i + 1)
                    };
                _table.Rows.Add(newRow);
            }

            _view       = new DataView(_table);
            _dataSource = new BindingSource(_view, "");

        }

        protected void InitializeEventSettings(){

            btnDoFilter.Click += (s, e) => {

                if(string.IsNullOrEmpty(_view.RowFilter)){

                    _view.RowFilter = "ID > 500 AND ID <= 510";

                }else{

                    _view.RowFilter = string.Empty;

                }

            };

            btnDoDistinct.Click += (s, e) => {
                //
                // 現在表示しているビュー上の重複する行を取り除いて表示する。
                //
                // 本イベントハンドラは以下の動作を行います。
                //
                // 1.現在表示されているデータテーブルが元のデータテーブルの場合
                //      ⇒現在表示しているビューデータから重複行を取り除いたデータを表示.
                // 2.現在表示されているデータテーブルが元のデータテーブルと違う場合
                //      ⇒元のデータテーブルに戻す.
                //
                DataTable currentTable = _view.Table;
                if(currentTable.TableName == _table.TableName){
                    //
                    // 重複行判定対象となるカラム名の配列を作成.
                    // (ここで指定するカラム名が重複判定対象列であると共にToTableメソッドにて
                    //  返却される列になります。)
                    //
                    string[] colNames = new string[_table.Columns.Count];
                    for(int i = 0; i < _table.Columns.Count; i++){
                        colNames[i] = _table.Columns[i].ColumnName;
                    }

                    //
                    // 重複行を取り除いた新たなデータテーブルを抽出.
                    //
                    bool      isDistinct    = true;
                    DataTable filteredTable = _view.ToTable("FILTERED_TABLE", isDistinct, colNames);

                    //
                    // 抽出したデータテーブルを新たなデータテーブルとする。
                    //
                    _view.Table = filteredTable;
                }else{

                    _view.Table = _table;

                }

            };

            grdMain.DataError += (s, e) => {
                MessageBox.Show(e.Exception.Message);
            };

        }

        protected void InitializeDataBindings(){
            
            grdMain.DataSource = _dataSource;

        }

        [STAThread]
        static void Main(){
            Application.EnableVisualStyles();
            Application.Run(new DemoForm());
        }
    }
}


上記をコンパイルして実行すると、画面が起動します。
ボタンが2つありまして、Do Filterボタンを押下すると行フィルターが
適用されます。
また、Do Distinctボタンをすると現在の表示データから重複行を取り除いた
データとなります。

*1:btnDoFilter.Width + 10), 0); grdMain = new DataGridView(); grdMain.AutoGenerateColumns = true; grdMain.EditMode = DataGridViewEditMode.EditOnEnter; grdMain.Size = new Size(500, 300); grdMain.Location = new Point(0, (btnDoDistinct.Height + 10