sql >> Database >  >> RDS >> Mysql

Flatten Table Pivot-stijl voor een Datagridview

Afhankelijk van wat u doet, kunt u in sommige gevallen een query of een voorbereide instructie maken om dit voor u te doen. Deze zijn meestal bedoeld om een ​​vaste set bekende kolommen samen te vatten. In dit geval weten we niet hoeveel datumkolommen er zullen zijn of wat ze zijn. We kunnen het dus in code doen.

Ik gebruikte Access in plaats van mySQL, maar het concept is hetzelfde. Ik heb het ook ingewikkelder gemaakt door de aanwezigheid per klas bij te houden die niet elke dag samenkomt. De startgegevens:

Ik zal de klassenaam niet gebruiken in de resultaten, dit maakt het scherm te breed.

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

Het is niet zo ingewikkeld als het lijkt.

  1. De masterdataset aan het werk zetten
  2. Krijg een lijst met unieke studentennamen
  3. De te gebruiken kolomnamen zijn afkomstig van een linq-query om de unieke klassedatums in de gegevenstabel te extraheren
  4. Maak een nieuwe DataTable voor de resultaten.
    • Na de StudentName en ClassCode een lus voegt één kolom toe voor elke datum die elke klas ontmoet. De kolomnamen/koptekst komt uit de ColNames lijst/array zojuist gemaakt.

Als de doel-DataTable is gemaakt, kunt u beginnen met het kopiëren van gegevens ernaar. Nogmaals, in plaats van OleDB... objecten die u zou gebruiken MySQL... object, maar ze werken hetzelfde.

  1. Doorloop alle studenten in de studentenlijst
  2. Haal voor elk een lijst op van alle lessen die ze hebben bijgewoond uit de masterdataset
  3. Loop door die lessen
  4. De rijen voor de huidige klas extraheren uit de dataset Student-Class
  5. Maak een nieuwe DataRow met behulp van de Student en Class iteratie vars voor de eerste 2 kolommen.
  6. Converteer elke DateTime-waarde in de huidige Student-Class-gegevensset naar dezelfde indeling die is gebruikt om de resultaatkolommen te maken (cname ).
    • gebruik het om hun status te kopiëren:newRow.Item(cname) = statRow.Item("Status") naar de nieuwe rij
    • Omdat de klassen elkaar niet elke dag ontmoeten, zijn sommige cellen leeg (DbNull )
  7. Voeg de nieuwe rij toe aan de laatste gegevenstabel

Het zou eenvoudiger zijn zonder de By Class-rapportage en rapporteer gewoon de status voor de hele dag. Het resultaat:

Het meest verwarrende deel is het gebruik van de Datum gegevens in één gegevenstabel als een kolom naam in een ander en het tijdsgedeelte eruit halen.

Dat is slechts een eerste doorgang, dus het kan waarschijnlijk worden verfijnd. Een deel van de verwerking kan mogelijk in SQL worden uitgevoerd; de DateTime.Parse methode om de DateTime . te converteren data naar een string in hetzelfde formaat (verwijder de tijd enz.) kan zijn eigen procedure zijn. Ik zou ook een jaarnotatie van 2 tekens gebruiken om de koppen wat smaller te maken.




  1. Kan geen overeenkomende rij vinden in de gebruikerstabel

  2. Hoeveel sneller is de tijdstempel dan de datetime-kolom in MySQL?

  3. Postgres-trigger na invoegen toegang tot NIEUW

  4. Big Query-variabelen instellen, zoals mysql