Beroende på vad du gör kan du i vissa fall skapa en fråga eller ett förberedt uttalande för att göra detta åt dig. Dessa är vanligtvis för att sammanfatta en fast uppsättning kända kolumner. I det här fallet vet vi inte hur många datumkolumner det kommer att finnas eller vad de är. Så vi kan göra det i kod.
Jag använde Access istället för mySQL, men konceptet är detsamma. Jag gjorde det också mer komplext genom att logga närvaro per klass som inte träffas varje dag. Startdata:
Jag kommer inte att använda klassnamnet i resultaten, det gör displayen för bred.
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
Det är inte riktigt så komplicerat som det kan se ut.
- Få huvuduppsättningen att arbeta med
- Få en lista med unika elevnamn
- Kolumnnamnen som ska användas kommer från en linq-fråga för att extrahera de unika klassdatumen i datatabellen
- Skapa en ny
DataTable
för resultaten.- Efter
StudentName
ochClassCode
en loop lägger till en kolumn för varje datum som vilket som helst klass träffas. Kolumnnamnen/huvudtexten kommer frånColNames
lista/array har precis skapats.
- Efter
Med måldatatabellen skapad kan du börja kopiera data till den. Återigen, istället för OleDB...
objekt som du skulle använda MySQL...
objekt, men de fungerar likadant.
- Bläddra igenom alla elever i elevlistan
- För varje, extrahera en lista över alla klasser de deltog i från masterdatauppsättningen
- Gå igenom dessa klasser
- Extrahera raderna för den aktuella klassen från datauppsättningen Student-Klass
- Skapa en ny
DataRow
genom att använda vars för Elev och Klass iteration för de två första kolumnerna. - Konvertera varje DateTime-värde i den aktuella Student-Class-datauppsättningen till samma format som används för att skapa resultatkolumnerna (
cname
).- använd den för att kopiera deras status:
newRow.Item(cname) = statRow.Item("Status")
till den nya raden - Eftersom klasserna inte träffas varje dag kommer vissa celler att vara tomma (
DbNull
)
- använd den för att kopiera deras status:
- Lägg till den nya raden i den slutliga datatabellen
Det skulle vara enklare utan rapporteringen per klass, och bara rapportera status för hela dagen. Resultatet:
Den mest förvirrande delen är att använda Datum-data i en datatabell som en kolumn namn i en annan och ta bort tidsdelen.
Det är bara ett första pass, så det kan troligen förfinas. En del av bearbetningen kanske kan göras i SQL; DateTime.Parse
metod för att konvertera DateTime
data till en sträng i samma format (ta bort tiden etc.) kan vara sin egen procedur. Jag skulle också använda ett årsformat med två tecken för att göra rubrikerna lite smalare.