mysql - Datagridview 的展平表透视样式

标签 mysql vb.net datagridview

我想使用 datagridview (vb.net) 查看我的出勤表

这是我的示例表

Name   |    Date     |  Status  
-------+-------------+--------
John   | 08/08/2015  |   P
Mark   | 08/08/2015  |   A
James  | 08/08/2015  |   L
John   | 08/09/2015  |   A
Mark   | 08/09/2015  |   A
James  | 08/09/2015  |   A

这就是我想要的 datagridview 的样子:

NAME  | 08/08/2015 | 08/09/2015
------+------------+------------
John  |     P      |     A
Mark  |     A      |     A
James |     L      |     A

最佳答案

根据您正在执行的操作,在某些情况下您可以创建查询或准备好的语句来为您执行此操作。这些通常是总结一组固定的已知列。在这种情况下,我们不知道会有多少个日期列或它们是什么。所以,我们可以用代码来完成。

我使用 Access 而不是 mySQL,但概念是相同的。我还通过按类(class)记录出勤情况使事情变得更加复杂,而这些类(class)并不每天都见面。起始数据:

enter image description here

我不会在结果中使用类名,它会使显示太宽。

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

它并不像看起来那么复杂。

  1. 获取要处理的主数据集
  2. 获取唯一学生姓名列表
  3. 要使用的列名称来自 linq 查询,用于提取数据表中的唯一类日期
  4. 为结果创建一个新的DataTable
    • StudentNameClassCode之后,循环为任何类(class)遇到的每个日期添加一列。列名称/标题文本来自刚刚创建的 ColNames 列表/数组。

创建目标数据表后,您可以开始将数据复制到其中。同样,您可以使用 MySQL... 对象来代替 OleDB... 对象,但它们的工作原理是相同的。

  1. 循环遍历学生列表中的所有学生
  2. 对于每个人,从主数据集中提取他们参加的所有类(class)的列表
  3. 循环遍历这些类
  4. 从学生类(class)数据集中提取当前类(class)的行
  5. 使用前 2 列的 Student 和 Class 迭代变量创建一个新的 DataRow
  6. 将当前学生类数据集中的每个日期时间值转换为用于创建结果列的相同格式 (cname)。
    • 用它来复制其状态:newRow.Item(cname) = statRow.Item("Status") 到新行
    • 由于类(class)并非每天都见面,因此某些单元格将为空白 (DbNull)
  7. 将新行添加到最终数据表

没有按类别报告会更简单,只需报告一整天的状态即可。结果:

enter image description here

最令人困惑的部分是使用一个数据表中的日期数据作为另一个数据表中的名称列,并去掉时间部分。

这只是第一步,因此可能会进一步完善。某些处理可能可以用 SQL 完成;将 DateTime 数据转换为相同格式的字符串(删除时间等)的 DateTime.Parse 方法可以是它自己的过程。我还会使用 2 个字符的年份格式来使标题更窄一些。

关于mysql - Datagridview 的展平表透视样式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32485034/

相关文章:

vb.net - VB模拟按键

c# - 如何在 datagridview 的列中的文本框中显示选中复选框的数量?

vb.net - 从 DataGridView 选定单元格获取文本

php - 如何从表中获取随机行值并将其存储在数组中以单独调用

php - WordPress MySQL 错误 : Unknown storage engine 'InnoDB'

mysql - 将 MySQL 格式的 (Date_format,Case) 替换为 ms-access 格式的 (Format,IIF)

c# - 经过一段空闲时间后,图像未从数据库加载

javascript - JSON无效字符错误

javascript - 在 javascript 函数中获取中继器内的控件以进行验证

c# - 如何检测鼠标按下是否超出行调整大小区域