W zależności od tego, co robisz, w niektórych przypadkach możesz utworzyć zapytanie lub przygotowaną instrukcję, aby zrobić to za Ciebie. Są to zwykle podsumowanie ustalonego zestawu znanych kolumn. W tym przypadku nie wiemy, ile będzie kolumn dat ani jakie one są. Możemy to zrobić w kodzie.
Użyłem Access zamiast mySQL, ale koncepcja jest taka sama. Uczyniłem to również bardziej skomplikowanym, rejestrując frekwencję według klas, które nie spotykają się codziennie. Dane początkowe:
Nie będę używał nazwy klasy w wynikach, powoduje to, że ekran jest zbyt szeroki.
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
Nie jest tak skomplikowany, jak mogłoby się wydawać.
- Pobierz główny zbiór danych do pracy
- Uzyskaj listę unikalnych imion uczniów
- Nazwy kolumn do użycia pochodzą z zapytania linq w celu wyodrębnienia unikalnych dat klas w tabeli danych
- Utwórz nową
DataTable
dla wyników.- Po
StudentName
iClassCode
pętla dodaje jedną kolumnę na każdą datę dowolną klasa spełnia. Nazwy kolumn/tekst nagłówka pochodzą zColNames
lista/tablica właśnie utworzona.
- Po
Po utworzeniu docelowej tabeli DataTable możesz rozpocząć kopiowanie do niej danych. Ponownie, zamiast OleDB...
obiekty, których użyłbyś MySQL...
obiekt, ale działają tak samo.
- Przejdź przez wszystkich uczniów z listy uczniów
- Dla każdego z nich wyodrębnij listę wszystkich zajęć, w których uczestniczyli, z zestawu danych podstawowych
- Przejdź przez te klasy
- Wyodrębnij wiersze dla bieżącej klasy ze zbioru danych o klasie ucznia
- Utwórz nowy
DataRow
używając zmiennych iteracyjnych Student i Class dla pierwszych 2 kolumn. - Konwertuj każdą wartość DateTime w bieżącym zestawie danych klasy Student na ten sam format, który został użyty do utworzenia kolumn wyników (
cname
).- użyj go, aby skopiować ich status:
newRow.Item(cname) = statRow.Item("Status")
do nowego wiersza - Ponieważ zajęcia nie spotykają się codziennie, niektóre komórki będą puste (
DbNull
)
- użyj go, aby skopiować ich status:
- Dodaj nowy wiersz do końcowej tabeli danych
Byłoby prościej bez raportowania Według klasy i po prostu zgłaszaj stan dla całego dnia. Wynik:
Najbardziej zagmatwaną częścią jest użycie danych daty w jednej tabeli danych jako kolumna nazwa w innym i usuwając część czasu.
To tylko pierwszy krok, więc prawdopodobnie można go dopracować. Część przetwarzania może być wykonana w SQL; DateTime.Parse
metoda konwersji DateTime
dane do ciągu w tym samym formacie (usuń czas itp.) mogą być własną procedurą. Użyłbym również dwuznakowego formatu roku, aby nagłówki były nieco węższe.