Mysql
 sql >> Base de données >  >> RDS >> Mysql

Aplatir le style de tableau croisé dynamique pour un Datagridview

Selon ce que vous faites, dans certains cas, vous pouvez créer une requête ou une instruction préparée pour le faire pour vous. Il s'agit généralement de résumer un ensemble fixe de colonnes connues. Dans ce cas, nous ne savons pas combien de colonnes de date il y aura ni ce qu'elles sont. Donc, nous pouvons le faire en code.

J'ai utilisé Access au lieu de mySQL, mais le concept est le même. Je l'ai également rendu plus complexe en enregistrant les présences par classe qui ne se réunissent pas tous les jours. Les données de départ :

Je n'utiliserai pas le nom de la classe dans les résultats, cela rend l'affichage trop large.

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

Ce n'est pas aussi complexe qu'il y paraît.

  1. Obtenir l'ensemble de données maître sur lequel travailler
  2. Obtenir une liste de noms d'étudiants uniques
  3. Les noms de colonne à utiliser proviennent d'une requête linq pour extraire les dates de classe uniques dans la table de données
  4. Créer un nouveau DataTable pour les résultats.
    • Après le StudentName et ClassCode une boucle ajoute une colonne pour chaque date que tout la classe se rencontre. Les noms de colonne/texte d'en-tête proviennent de ColNames liste/tableau vient d'être créé.

Une fois le DataTable de destination créé, vous pouvez commencer à y copier des données. Encore une fois, au lieu de OleDB... objets que vous utiliseriez MySQL... objet, mais ils fonctionnent de la même manière.

  1. Parcourir tous les étudiants de la liste des étudiants
  2. Pour chacun, extrayez une liste de toutes les classes qu'ils ont suivies à partir de l'ensemble de données de base
  3. Parcourir ces classes
  4. Extraire les lignes de la classe actuelle de l'ensemble de données Student-Class
  5. Créer un nouveau DataRow en utilisant les variables d'itération Student et Class pour les 2 premières colonnes.
  6. Convertissez chaque valeur DateTime de l'ensemble de données Student-Class actuel dans le même format que celui utilisé pour créer les colonnes de résultats (cname ).
    • utilisez-le pour copier leur statut :newRow.Item(cname) = statRow.Item("Status") à la nouvelle ligne
    • Étant donné que les cours ne se réunissent pas tous les jours, certaines cellules seront vides (DbNull )
  7. Ajouter la nouvelle ligne au tableau de données final

Ce serait plus simple sans le rapport Par classe, et il suffit de signaler le statut pour toute la journée. Le résultat :

La partie la plus déroutante consiste à utiliser les données de date dans une table de données en tant que colonne nom dans un autre et en supprimant la portion de temps.

Ce n'est qu'un premier passage, il peut donc être affiné. Une partie du traitement peut être effectuée en SQL ; le DateTime.Parse méthode pour convertir le DateTime données à une chaîne dans le même format (supprimer l'heure, etc.) pourrait être sa propre procédure. J'utiliserais également un format d'année à 2 caractères pour rendre les en-têtes un peu plus étroits.