如何使用数据填充datagridview,具体取决于数据库列中的值

时间:2018-04-25 13:56:31

标签: sql datagridview visual-foxpro

我们说我有一个数据库表' USAGE'如下所示:

MACHINE     WEEK        HOURS       PIECES
A           2018-12     1           2
B           2018-12     3           4
A           2018-13     12          1
B           2018-13     2           5
A           2018-15     6           6
B           2018-15     2           2
C           2018-16     2           1
D           2018-17     4           22
B           2018-17     3           9
A           2018-18     1           8
E           2018-18     4           4
D           2018-13     2           4

我希望在datagridview中显示数据如下:

MACHINE     2018-12     2018-13     2018-14     2018-15     2018-16     2018-17     2018-18
A           1H 2P       12H 1P                  6H 6P                               1H 8P
B           3H 4P       2H 5P                   2H 2P                   3H 9P
C                                                           2H 1P
D                       2H 4P                                           4H 22P
E                                                                                   4H 4P

在视觉狐狸中,这非常简单。

this.edType      = 1
this.ehCols      = 20
this.ehStartval  = date()+ 7

这创建了20个列,标题中包含不同的周数。然后用下面的命令完成了:

this.ehKeyFld    = "iif(usage.hours > 0 and usage.pieces > 0,STR(usage.hours,4) + 'H ' + STR(usage.pieces,3)+'P','')"

现在我想做同样的事情,但我喜欢在datagridview中显示数据。

如果我这样做:

select machine, iif(week='2018-12',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-12', IIF(week='2018-13',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-13', IIF(week='2018-14',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-14', IIF(week='2018-15',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-15', IIF(week='2018-16',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-16', IIF(week='2018-17',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-17', IIF(week='2018-18',str(hours,4) + 'H' + str(pieces,3) + 'P','') as '2018-18' from GCCTEST.dbo.usage

我得到以下输出:

machine 2018-12 2018-13 2018-14 2018-15 2018-16 2018-17 2018-18
A       1H  2P                      
B       3H  4P                      
A               12H  1P                 
B               2H  5P                  
A                               6H  6P          
B                               2H  2P          
C                                       2H  1P      
D                                               4H 22P  
B                                               3H  9P  
A                                                       1H  8P
E                                                       4H  4P
D               2H  4P                  

我在SQL中寻找一个可以按照我想要的方式填充datagridview的命令,即每一台机器都有一行,数据在正确的列中。

3 个答案:

答案 0 :(得分:1)

我接受VFP更容易。但是,说datagridview,我认为你的意思是C#,这也可以用C#在很多方面完成。使用SQL,您还可以使用“PIVOT”。即:

DECLARE @table TABLE([MACHINE] VARCHAR(1), [WEEK] VARCHAR(7), [HOURS] INT, [PIECES] INT);

INSERT INTO @table(MACHINE, WEEK, HOURS, PIECES)
VALUES('A', '2018-12', 1, 2),
    ('B', '2018-12', 3, 4),
    ('A', '2018-13', 12, 1),
    ('B', '2018-13', 2, 5),
    ('A', '2018-15', 6, 6),
    ('B', '2018-15', 2, 2),
    ('C', '2018-16', 2, 1),
    ('D', '2018-17', 4, 22),
    ('B', '2018-17', 3, 9),
    ('A', '2018-18', 1, 8),
    ('E', '2018-18', 4, 4),
    ('D', '2018-13', 2, 4);

SELECT *
FROM(
    SELECT MACHINE, WEEK, STR(HOURS, 4)+'H'+STR(PIECES, 3)+'P' AS data
    FROM @table
    ) AS source
PIVOT(
     MAX(data)
     FOR WEEK IN([2018-12], [2018-13], [2018-14], [2018-15], [2018-16], [2018-17], [2018-18])
     ) AS mypivot;

但是,您不希望在SQL中对所有这些列进行硬编码。检查“动态PIVOT”。以下是Northwind数据的示例:

DECLARE @COUNTRY NVARCHAR(MAX) = '' , @cTotal NVARCHAR(MAX) = ''

SELECT  @COUNTRY = @COUNTRY + COALESCE(QUOTENAME(Country) + ', ', '')
FROM    Customers
WHERE   EXISTS ( SELECT *
                 FROM   [Orders] AS [o]
                 WHERE  o.[CustomerID] = Customers.[CustomerID] )
GROUP BY Country;

SET @COUNTRY = LEFT(@COUNTRY, LEN(@COUNTRY) - 1);

SELECT  @cTotal = @cTotal + COALESCE('Coalesce('+QUOTENAME(Country) + ',0) +', '')
FROM    Customers
WHERE   EXISTS ( SELECT *
                 FROM   [Orders] AS [o]
                 WHERE  o.[CustomerID] = Customers.[CustomerID] )
GROUP BY Country;

SET @cTotal = LEFT(@cTotal, LEN(@cTotal) - 1);

DECLARE @SQL NVARCHAR(MAX);

SET @SQL = 'SELECT * , ' + @cTotal + ' AS TOTAL FROM 
    (
        SELECT  oe.EmployeeID, oe.LastName, oe.ShipCountry AS CO,
                OD.Quantity * OD.UnitPrice AS QU
        FROM    (
                  SELECT  EmployeeID, LastName, ShipCountry
                  FROM    (
                            SELECT DISTINCT
                                    ShipCountry
                            FROM    Orders
                          ) o ,
                          Employees
                ) oe
        LEFT JOIN Orders O ON O.EmployeeID = oe.EmployeeID AND
                              [oe].[ShipCountry] = [O].[ShipCountry]
        LEFT JOIN [Order Details] OD ON OD.OrderID = O.OrderID 
    ) AS T
    PIVOT(SUM(QU) FOR CO IN (' + @COUNTRY + ')) AS PVT
    ORDER BY 1';

EXEC(@SQL); 

答案 1 :(得分:1)

我的解决方案: 我有一个数据库,其中包含tblMachines中机器的描述,我有一个数据库,其中包含tblUsage中机器的用法。 在我的Windows窗体上,我有一个datagridview Dgv_4和一个Combobox1

Private Sub ComboBox_Drop(sender As Object, e As EventArgs) Handles ComboBox1.DropDown
    Dim ac As ComboBox = DirectCast(sender, ComboBox)
    If Me.ActiveControl Is ComboBox1 Then
        ComboBox1.Items.Clear()
        ' Fill combobox with a range of weeks to chose from
        For i As Integer = -1 To 1 Step 1
            For j As Integer = 1 To 52
                Dim num As String = j.ToString
                If Len(num) < 2 Then
                    num = $"0{num}"
                End If
                ComboBox1.Items.Add(Date.Today.Year + i & "-" & num)
            Next
        Next
    End If
End Sub

Private Sub ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
    ' Create headers for datagridview with dates and weeknumbers
    Dim result As String = ComboBox1.SelectedItem
    Dim PivotString As String = $"PIVOT (MAX(data) FOR week IN("
    Dim endline As String = ","
    Dim weekadd As Integer = 0
    For i As Integer = 0 To TotNumWeeks
        If i = TotNumWeeks Then
            ' Close string
            endline = ")) as mypivot"
        Else
            ' Check year limits
            If (Convert.ToInt32(Strings.Right(result, 2)) + i) > 52 Then
                ' Change year and week
                weekadd = 0
                result = $"{Convert.ToInt32(Strings.Left(result, 4)) + 1.ToString}-01"
            End If
        End If
        PivotString = PivotString + $"[{Strings.Left(result, 4)}-{(Convert.ToInt32(Strings.Right(result, 2)) + weekadd).ToString("D2")}]{endline}"
        weekadd = weekadd + 1
    Next
    Dgv_4Pivot = PivotString
    ' Run query without pivot, seems to prevent insert columns on the right
    LoadDataGridView1($"SELECT {Dgv_4Query}{Dgv_4Join}")
    ' Run query with pivot to fill datagridview with new weeks
    LoadDataGridView1($"SELECT * FROM (SELECT {Dgv_4Query}{Dgv_4Join}) as source {Dgv_4Pivot} order by prio", "")
End Sub

这将从当前周开始显示并加载datagridview,使用组合框可以选择不同的星期:

{{1}}

输出示例:https://imgur.com/a/DTtloNz

答案 2 :(得分:0)

我也发现在SQL中更难做到.Net缺乏VFP的活力&lt; g>你可能仍然可以通过自己的一些自定义数据来解决这个问题。枢轴通常在VFP中称为交叉表。实际上它是关于汇总数据然后分发到列,其中一列值(此处为机器)被转换为列。在您的示例中,数据已经汇总,实际上不需要使用MS SQL的数据透视表。恕我直言,可以获取数据并在数据表中本地创建交叉表,因为您只有大约20-25列(周),最多可能有一千台机器。以下是采样代码(使用telerik代码转换器从C#转换代码 - 注意:我昨天使用MS SQL服务器基础查询来模仿您的数据来自MS SQL):

Private Sub Main()
    Dim sql As String = "DECLARE @table TABLE([MACHINE] VARCHAR(1), [WEEK] VARCHAR(7), [HOURS] INT, [PIECES] INT);

INSERT INTO @table(MACHINE, WEEK, HOURS, PIECES)
VALUES('A', '2018-12', 1, 2),
    ('B', '2018-12', 3, 4),
    ('A', '2018-13', 12, 1),
    ('B', '2018-13', 2, 5),
    ('A', '2018-15', 6, 6),
    ('B', '2018-15', 2, 2),
    ('C', '2018-16', 2, 1),
    ('D', '2018-17', 4, 22),
    ('B', '2018-17', 3, 9),
    ('A', '2018-18', 1, 8),
    ('E', '2018-18', 4, 4),
    ('D', '2018-13', 2, 4);

    SELECT MACHINE, WEEK, HOURS, PIECES FROM @table"
    Dim tbl As DataTable = New DataTable()
    Using con = New SqlConnection("server=.\SQLExpress;Trusted_Connection=yes")
        con.Open()
        tbl.Load(New SqlCommand(sql, con).ExecuteReader())
        con.Close()
    End Using

    Dim weeks = 20
    Dim weekStart = 12
    Dim year = 2018
    Dim result As DataTable = New DataTable()
    result.Columns.Add("Machine", GetType(String))
    For i As Integer = 0 To weeks - 1
        Dim week = $"{year}-{i + weekStart}"
        result.Columns.Add(week, GetType(String))
    Next

    Dim lst = tbl.AsEnumerable()
    Dim machines = lst.[Select](Function(l) l.Field(Of String)("Machine")).Distinct().OrderBy(Function(l) l)
    For Each machine As String In machines
        Dim row = result.NewRow()
        row("Machine") = machine
        For i As Integer = 0 To weeks - 1
            Dim week = $"{year}-{i + weekStart}"
            Dim weekValue = lst.SingleOrDefault(Function(t) t.Field(Of String)("WEEK") = week AndAlso t.Field(Of String)("Machine") = machine)
            row(week) = If(weekValue Is Nothing, "", $"{CInt(weekValue("Hours"))}H {CInt(weekValue("Pieces"))}P")
        Next

        result.Rows.Add(row)
    Next

    Dim f As Form = New Form()
    f.Controls.Add(New DataGridView With {.Dock = DockStyle.Fill, .DataSource = result})
    f.Show()
End Sub