何をしているかによっては、クエリまたはプリペアドステートメントを作成してこれを行うことができる場合があります。これらは通常、既知の列の固定セットを要約するためのものです。この場合、日付列がいくつあるか、またはそれらが何であるかはわかりません。したがって、コードでそれを行うことができます。
mySQLの代わりにAccessを使用しましたが、概念は同じです。また、毎日会わないクラスごとの出席を記録することで、より複雑にしました。開始データ:
結果にクラス名を使用しないと、表示が広すぎます。
Dim sql = <sql>
((Use your own SQL obviously))
</sql>.Value
Dim dtTemp As New DataTable
' get the data
Using dbcon As OleDbConnection = GetACEConnection(),
cmd As New OleDbCommand(sql, dbcon)
dbcon.Open()
Using da As New OleDbDataAdapter(cmd)
da.Fill(dtTemp)
End Using
End Using
' unique list of "date" columns in the result set
' ORDERBY Date is in the SQL
Dim colNames = dtTemp.AsEnumerable().
Select(Function(s) DateTime.Parse(s.Item("Date").ToString).
ToString("MM/dd/yyyy")).
Distinct.ToList()
' unique list of students
Dim Students = dtTemp.AsEnumerable().Select(Function(q) q.Item("Name")).
Distinct.ToList()
' the final table to use with the DGV
Dim dt As New DataTable
Dim colName As String
' add the name and class code designation columns
dt.Columns.Add(New DataColumn(dtTemp.Columns(0).ColumnName, GetType(String)))
dt.Columns.Add(New DataColumn(dtTemp.Columns(1).ColumnName, GetType(String)))
' add a "MM/dd/yyyy" text column for each possible class day
For n As Int32 = 0 To colNames.ToArray.Count - 1
colName = DateTime.Parse(colNames(n).ToString).ToString("MM/dd/yyyy")
dt.Columns.Add(New DataColumn(colName, GetType(String)))
Next
Dim newRow As DataRow
' loop thru all students
For Each s In Students
' the student-class dataset
Dim drs As DataRow() = dtTemp.Select(String.Format("Name = '{0}'", s.ToString)).
OrderBy(Function(o) o.Item("ClassCode")).ToArray
' create list of classes for this student
Dim classes = drs.AsEnumerable.
Select(Function(q) q.Item(1).ToString).Distinct.ToArray
For Each classcode As String In classes
' filter the drs results to the current class
Dim datestat As DataRow() = drs.AsEnumerable.
Where(Function(q) q.Item(1).ToString = classcode).ToArray
' create new row, copy the data from drs.Rows to dt.columns
newRow = dt.NewRow
newRow.Item(0) = s
newRow.Item(1) = classcode
' NOTE since not all students will have a class everyday, some
' "status" cells will be dbNull!
For Each statRow In datestat
Dim cname As String = DateTime.Parse(statRow.Item("Date").
ToString()).ToString("MM/dd/yyyy")
newRow.Item(cname) = statRow.Item("Status")
Next
dt.Rows.Add(newRow)
Next
Next
dgv.AutoGenerateColumns = True
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader)
dgv.DataSource = dt
見た目ほど複雑ではありません。
- マスターデータセットを取得して作業する
- 一意の学生名のリストを取得する
- 使用する列名は、データテーブル内の一意のクラス日付を抽出するためのlinqクエリから取得されます
- 新しい
DataTable
を作成します 結果のために。-
StudentName
の後 およびClassCode
ループは、任意の日付ごとに1つの列を追加します クラスが出会う。列名/ヘッダーテキストはColNames
から取得されます 作成したばかりのリスト/配列。
-
宛先のDataTableが作成されたら、そこへのデータのコピーを開始できます。繰り返しますが、OleDB...
の代わりに MySQL...
を使用するオブジェクト オブジェクトですが、同じように機能します。
- 生徒リストのすべての生徒をループします
- それぞれについて、マスターデータセットから参加したすべてのクラスのリストを抽出します
- これらのクラスをループします
- Student-Classデータセットから現在のクラスの行を抽出します
- 新しい
DataRow
を作成します 最初の2列にStudentとClassの反復変数を使用します。 - 現在のStudent-Classデータセットの各DateTime値を、結果列の作成に使用したのと同じ形式に変換します(
cname
)。- ステータスをコピーするために使用します:
newRow.Item(cname) = statRow.Item("Status")
新しい行へ - クラスは毎日会わないため、一部のセルは空白になります(
DbNull
)
- ステータスをコピーするために使用します:
- 新しい行を最終的なデータテーブルに追加します
クラス別レポートがない方が簡単で、1日全体のステータスをレポートするだけです。結果:
最も紛らわしいのは、日付データの使用です。 1つのデータテーブル内の列name 別の時間部分を取り除きます。
これは最初のパスにすぎないため、改良できる可能性があります。一部の処理はSQLで実行できる場合があります。 DateTime.Parse
DateTime
を変換するメソッド 同じ形式の文字列へのデータ(時刻の削除など)は、独自の手順である可能性があります。また、ヘッダーを少し狭くするために2文字の年形式を使用します。