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

Flatten Table Pivot-stil til en Datagridview

Afhængigt af hvad du laver, kan du i nogle tilfælde oprette en forespørgsel eller udarbejdet erklæring for at gøre dette for dig. Disse er normalt for at opsummere et fast sæt af kendte kolonner. I dette tilfælde ved vi ikke, hvor mange datokolonner der vil være, eller hvad de er. Så vi kan gøre det i kode.

Jeg brugte Access i stedet for mySQL, men konceptet er det samme. Jeg gjorde det også mere komplekst ved at logge fremmøde efter klasse, som ikke mødes hver dag. Startdata:

Jeg vil ikke bruge klassenavnet i resultaterne, det gør skærmen for 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 er ikke helt så komplekst, som det kan se ud.

  1. Få masterdatasættet til at arbejde på
  2. Få en liste over unikke elevnavne
  3. Kolonnenavnene, der skal bruges, kommer fra en linq-forespørgsel til at udtrække de unikke klassedatoer i datatabellen
  4. Opret en ny DataTable for resultaterne.
    • Efter StudentName og ClassCode en løkke tilføjer én kolonne for hver dato, som enhver klasse mødes. Kolonnenavnene/overskriftsteksten kommer fra ColNames liste/array lige oprettet.

Når destinationsdatatabellen er oprettet, kan du begynde at kopiere data til den. Igen, i stedet for OleDB... objekter du ville bruge MySQL... objekt, men de fungerer på samme måde.

  1. Søg gennem alle elever på elevlisten
  2. For hver skal du udtrække en liste over alle klasser, de deltog i, fra masterdatasættet
  3. Gå gennem disse klasser
  4. Udtræk rækkerne for den aktuelle klasse fra Elev-Klasse-datasættet
  5. Opret en ny DataRow ved at bruge Elev- og Klasse-iterationen vars for de første 2 kolonner.
  6. Konverter hver DateTime-værdi i det aktuelle Student-Class-datasæt til det samme format, som bruges til at oprette resultatkolonnerne (cname ).
    • brug den til at kopiere deres status:newRow.Item(cname) = statRow.Item("Status") til den nye række
    • Da klasserne ikke mødes hver dag, vil nogle celler være tomme (DbNull )
  7. Tilføj den nye række til den endelige datatabel

Det ville være nemmere uden rapportering efter klasse, og bare rapportere status for hele dagen. Resultatet:

Den mest forvirrende del er at bruge Dato data i én datatabel som en kolonne navn i en anden og fjerner tidsdelen.

Det er kun en første omgang, så den kan sandsynligvis forfines. Noget af behandlingen kan muligvis udføres i SQL; DateTime.Parse metode til at konvertere DateTime data til en streng i samme format (fjern klokkeslættet osv.) kunne være sin egen procedure. Jeg ville også bruge et årstal med 2 tegn for at gøre overskrifterne lidt smallere.




  1. Søg i alle tabeller, alle kolonner for en bestemt værdi SQL Server

  2. pyodbc + MySQL + Windows:Datakildenavn blev ikke fundet og ingen standarddriver angivet

  3. Omvendt af SQL LIKE '%value%'

  4. Sådan fjerner du "X Rows Selected" i SQLcl &SQL*Plus (Oracle)