Mysql
 sql >> Database >  >> RDS >> Mysql

Appiattisci lo stile pivot della tabella per una vista Datagrid

A seconda di ciò che stai facendo, in alcuni casi puoi creare una query o una dichiarazione preparata per farlo per te. Di solito servono a riassumere un insieme fisso di colonne note. In questo caso non sappiamo quante colonne di data ci saranno o quali siano. Quindi, possiamo farlo in codice.

Ho usato Access invece di MySQL, ma il concetto è lo stesso. L'ho anche reso più complesso registrando le presenze per classe che non si incontrano tutti i giorni. I dati di partenza:

Non userò il nome della classe nei risultati, rende il display troppo ampio.

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

Non è così complesso come potrebbe sembrare.

  1. Ottieni il set di dati principale su cui lavorare
  2. Ottieni un elenco di nomi di studenti univoci
  3. I nomi delle colonne da utilizzare provengono da una query linq per estrarre le date delle classi univoche nella tabella dei dati
  4. Crea una nuova DataTable per i risultati.
    • Dopo il StudentName e ClassCode un ciclo aggiunge una colonna per ogni data che qualsiasi la classe si incontra. I nomi delle colonne/il testo dell'intestazione deriva da ColNames elenco/array appena creato.

Con il DataTable di destinazione creato, puoi iniziare a copiare i dati su di esso. Di nuovo, invece di OleDB... oggetti che useresti MySQL... oggetto, ma funzionano allo stesso modo.

  1. Scorri tutti gli studenti nell'elenco degli studenti
  2. Per ciascuno, estrai un elenco di tutte le lezioni a cui hanno partecipato dal set di dati principali
  3. Scorri queste classi
  4. Estrai le righe per la classe corrente dal set di dati Student-Class
  5. Crea un nuovo DataRow utilizzando le variabili di iterazione Studente e Classe per le prime 2 colonne.
  6. Converti ogni valore DateTime nell'attuale dataset Student-Class nello stesso formato utilizzato per creare le colonne dei risultati (cname ).
    • usalo per copiare il loro stato:newRow.Item(cname) = statRow.Item("Status") alla nuova riga
    • Dato che le classi non si incontrano tutti i giorni, alcune celle saranno vuote (DbNull )
  7. Aggiungi la nuova riga al datatable finale

Sarebbe più semplice senza il report Per classe e riportare solo lo stato per l'intera giornata. Il risultato:

La parte più confusa è l'utilizzo dei dati della data in un datatable come colonna nome in un altro ed eliminando la parte del tempo.

Questo è solo un primo passaggio, quindi può probabilmente essere perfezionato. Alcune delle elaborazioni potrebbero essere eseguite in SQL; il DateTime.Parse metodo per convertire il DateTime dati in una stringa nello stesso formato (rimuovere l'ora ecc.) potrebbe essere la propria procedura. Userei anche un formato anno a 2 caratteri per rendere le intestazioni un po' più strette.