В зависимост от това, което правите, в някои случаи можете да създадете заявка или подготвен изявление, за да направите това вместо вас. Те обикновено са за обобщаване на фиксиран набор от известни колони. В този случай не знаем колко колони за дата ще има или какви са те. Така че можем да го направим в код.
Използвах Access вместо mySQL, но концепцията е същата. Освен това го направих по-сложно, като регистрирах присъствието по класове, които не се срещат всеки ден. Началните данни:
Няма да използвам името на класа в резултатите, това прави дисплея твърде широк.
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
цикъл добавя една колона за всяка дата, коятокоято и да е клас се среща. Имената на колоните/текстът на заглавката идват отColNames
списък/масив току-що създаден.
- След
Със създадената цел DataTable можете да започнете да копирате данни в нея. Отново вместо OleDB...
обекти, които бихте използвали MySQL...
обект, но работят по същия начин.
- Прегледайте всички ученици в списъка с ученици
- За всеки извлечете списък с всички класове, които са посещавали, от основния набор от данни
- Прегледайте тези класове
- Извлечете редовете за текущия клас от набора от данни Student-Class
- Създайте нов
DataRow
с помощта на итерациите на ученик и клас за първите 2 колони. - Преобразувайте всяка стойност на DateTime в текущия набор от данни на Student-Class в същия формат, използван за създаване на колоните с резултати (
cname
).- използвайте го, за да копирате състоянието им:
newRow.Item(cname) = statRow.Item("Status")
към новия ред - Тъй като класовете не се срещат всеки ден, някои клетки ще бъдат празни (
DbNull
)
- използвайте го, за да копирате състоянието им:
- Добавете новия ред към крайната таблица с данни
Би било по-лесно без отчитането по клас и просто докладвайте състоянието за целия ден. Резултатът:
Най-объркващата част е използването на данните за дата в една таблица с данни като колона име в друг и премахване на времевата част.
Това е само първо преминаване, така че вероятно може да бъде прецизирано. Част от обработката може да бъде извършена в SQL; DateTime.Parse
метод за преобразуване на DateTime
данни към низ в същия формат (премахване на Time и т.н.) може да бъде собствена процедура. Също така бих използвал 2-символен годишен формат, за да направя заглавките малко по-тесни.