Afhængigt af hvad du laver, kan du i nogle tilfælde oprette en forespørgsel eller udarbejdet erklæring for at gøre dette for dig. Disse er normalt for at opsummere et fast sæt af kendte kolonner. I dette tilfælde ved vi ikke, hvor mange datokolonner der vil være, eller hvad de er. Så vi kan gøre det i kode.
Jeg brugte Access i stedet for mySQL, men konceptet er det samme. Jeg gjorde det også mere komplekst ved at logge fremmøde efter klasse, som ikke mødes hver dag. Startdata:
Jeg vil ikke bruge klassenavnet i resultaterne, det gør skærmen for 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 er ikke helt så komplekst, som det kan se ud.
- Få masterdatasættet til at arbejde på
- Få en liste over unikke elevnavne
- Kolonnenavnene, der skal bruges, kommer fra en linq-forespørgsel til at udtrække de unikke klassedatoer i datatabellen
- Opret en ny
DataTable
for resultaterne.- Efter
StudentName
ogClassCode
en løkke tilføjer én kolonne for hver dato, som enhver klasse mødes. Kolonnenavnene/overskriftsteksten kommer fraColNames
liste/array lige oprettet.
- Efter
Når destinationsdatatabellen er oprettet, kan du begynde at kopiere data til den. Igen, i stedet for OleDB...
objekter du ville bruge MySQL...
objekt, men de fungerer på samme måde.
- Søg gennem alle elever på elevlisten
- For hver skal du udtrække en liste over alle klasser, de deltog i, fra masterdatasættet
- Gå gennem disse klasser
- Udtræk rækkerne for den aktuelle klasse fra Elev-Klasse-datasættet
- Opret en ny
DataRow
ved at bruge Elev- og Klasse-iterationen vars for de første 2 kolonner. - Konverter hver DateTime-værdi i det aktuelle Student-Class-datasæt til det samme format, som bruges til at oprette resultatkolonnerne (
cname
).- brug den til at kopiere deres status:
newRow.Item(cname) = statRow.Item("Status")
til den nye række - Da klasserne ikke mødes hver dag, vil nogle celler være tomme (
DbNull
)
- brug den til at kopiere deres status:
- Tilføj den nye række til den endelige datatabel
Det ville være nemmere uden rapportering efter klasse, og bare rapportere status for hele dagen. Resultatet:
Den mest forvirrende del er at bruge Dato data i én datatabel som en kolonne navn i en anden og fjerner tidsdelen.
Det er kun en første omgang, så den kan sandsynligvis forfines. Noget af behandlingen kan muligvis udføres i SQL; DateTime.Parse
metode til at konvertere DateTime
data til en streng i samme format (fjern klokkeslættet osv.) kunne være sin egen procedure. Jeg ville også bruge et årstal med 2 tegn for at gøre overskrifterne lidt smallere.