sql >> Databasteknik >  >> RDS >> Mysql

Platta tabellpivotstil för en Datagridview

Beroende på vad du gör kan du i vissa fall skapa en fråga eller ett förberedt uttalande för att göra detta åt dig. Dessa är vanligtvis för att sammanfatta en fast uppsättning kända kolumner. I det här fallet vet vi inte hur många datumkolumner det kommer att finnas eller vad de är. Så vi kan göra det i kod.

Jag använde Access istället för mySQL, men konceptet är detsamma. Jag gjorde det också mer komplext genom att logga närvaro per klass som inte träffas varje dag. Startdata:

Jag kommer inte att använda klassnamnet i resultaten, det gör displayen för 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 är inte riktigt så komplicerat som det kan se ut.

  1. Få huvuduppsättningen att arbeta med
  2. Få en lista med unika elevnamn
  3. Kolumnnamnen som ska användas kommer från en linq-fråga för att extrahera de unika klassdatumen i datatabellen
  4. Skapa en ny DataTable för resultaten.
    • Efter StudentName och ClassCode en loop lägger till en kolumn för varje datum som vilket som helst klass träffas. Kolumnnamnen/huvudtexten kommer från ColNames lista/array har precis skapats.

Med måldatatabellen skapad kan du börja kopiera data till den. Återigen, istället för OleDB... objekt som du skulle använda MySQL... objekt, men de fungerar likadant.

  1. Bläddra igenom alla elever i elevlistan
  2. För varje, extrahera en lista över alla klasser de deltog i från masterdatauppsättningen
  3. Gå igenom dessa klasser
  4. Extrahera raderna för den aktuella klassen från datauppsättningen Student-Klass
  5. Skapa en ny DataRow genom att använda vars för Elev och Klass iteration för de två första kolumnerna.
  6. Konvertera varje DateTime-värde i den aktuella Student-Class-datauppsättningen till samma format som används för att skapa resultatkolumnerna (cname ).
    • använd den för att kopiera deras status:newRow.Item(cname) = statRow.Item("Status") till den nya raden
    • Eftersom klasserna inte träffas varje dag kommer vissa celler att vara tomma (DbNull )
  7. Lägg till den nya raden i den slutliga datatabellen

Det skulle vara enklare utan rapporteringen per klass, och bara rapportera status för hela dagen. Resultatet:

Den mest förvirrande delen är att använda Datum-data i en datatabell som en kolumn namn i en annan och ta bort tidsdelen.

Det är bara ett första pass, så det kan troligen förfinas. En del av bearbetningen kanske kan göras i SQL; DateTime.Parse metod för att konvertera DateTime data till en sträng i samma format (ta bort tiden etc.) kan vara sin egen procedur. Jag skulle också använda ett årsformat med två tecken för att göra rubrikerna lite smalare.




  1. Django och skrivskyddade databasanslutningar

  2. MySQL startar inte när du uppgraderar OSX till Yosemite eller El Capitan

  3. Hur man korrekt gör CREATE INDEX med SQLite

  4. Hur man delar en sträng efter ett specifikt tecken i SQL Server och uppdaterar detta värde till en specifik kolumn