0

我正在尝试将多行放入表中,因此我尝试获取行号并将其放入 for 循环中,这countC与 select 语句的行数完全相同,因此问题不存在

我正在使用 oledb 连接,因为我的代码在 vb asp.net 中,但我的数据库在 ms access 2003 中

For c As Integer = 1 To countC
        Dim cmdstring As String
        cmdstring = " INSERT INTO [KN - ProductionMachineAllocation] (BatchNo, ComponentID)       
                  SELECT POH.BatchNo, SSCDD.ComponentID
                FROM (
                    SELECT ROW_NUMBER() OVER (ORDER BY BatchNo ASC) AS rownumber
                    ([KN - ProductionOrderHeader] AS POH
                    INNER JOIN [FG - End Product Codes] AS EPC
                        ON POH.ProductID = EPC.ProductID)
                    INNER JOIN ([KN - ProductionOrderDetails] AS POD
                    INNER JOIN [FG - Style Size Comp Def Details]  AS SSCDD
                        ON POD.SizeID = SSCDD.SizeID) 
                        ON (POH.BatchNo = POD.BatchNo) 
                            AND (EPC.StyleID = SSCDD.StyleID)
                    WHERE POH.BatchNo = '" & BatchNo & "'
                     )  AS temptablename
                WHERE rownumber IN (" & c & ");"
        Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Shantara Production IT.mdb")
        Dim cmd As New OleDbCommand(cmdstring)
        cmd.CommandType = CommandType.Text
        cmd.Connection = con
        cmd.Connection.Open()
        cmd.ExecuteNonQuery()
        cmd.Connection.Close()
    Next

我发现 ms 访问不支持ROW_NUMBER(),所以我需要找到另一个遍历每一行,因为 ms 访问不支持通过插入到我的选择语句中插入多行,关于我的问题有什么建议吗?

4

2 回答 2

2

大多数数据库能够完全在数据库中更有效地完成所有这些工作。当然,在 SQL Server 中,我可以将整个事情归结为一个查询。Access 有点不同,因为 vbscript 是它的过程语言,而不是更像 t-sql 的东西。仍然可能有办法做到这一点,但既然你有工作,我们至少可以专注于让它变得更好。

GridViews 是视觉结构,会消耗额外的内存和资源。如果 Access 不会执行真正的 INSERT/SELECT,您至少可以直接从以前的结果集中读取到您的插入中。您还可以通过使用参数并为所有插入重新使用单个打开连接来显着改进这一点:

Dim cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Shantara Production IT.mdb"
Dim SQLDown As String = _
     "SELECT DISTINCT POH.BatchNo, SSCDD.ComponentID
      FROM ([KN - ProductionOrderHeader] AS POH
      INNER Join [FG - End Product Codes] AS EPC
        On POH.ProductID = EPC.ProductID)
      INNER Join([KN - ProductionOrderDetails] AS POD
      INNER Join [FG - Style Size Comp Def Details]  AS SSCDD
           On POD.SizeID = SSCDD.SizeID) 
           On (POH.BatchNo = POD.BatchNo) 
                And (EPC.StyleID = SSCDD.StyleID)
     WHERE POH.BatchNo = ? "
Dim SQLUp As String = _
    " INSERT INTO [KN - ProductionMachineAllocation] 
      (BatchNo, ComponentID) 
       VALUES( ?, ? )"

Dim dt As New DataTable
Using con As New OleDbConnection(cnString), _
      cmd As New OleDbCommand(SQLDown, con)

    'Guessing at parameter type/length here.
    'Use the actual column type and size from your DB
    cmd.Parameters.Add("@BatchNo", OleDbType.VarWChar, 10).Value = BatchNo

    con.Open()
    dt.Load(cmd.ExecuteReader())
End Using

Using con As New OleDbConnection(cnString), _
      cmd As New OleDbCommand(SqlUp, con)

    'Guessing at parameter types/lengths again
    cmd.Parameters.Add("@BatchNo", OleDbType.VarWChar, 10)
    cmd.Parameters.Add("@ComponentID", OleDbType.Integer)

    'Connection is managed *outside of the loop*. Only one object created, only one negotiation with DB
    con.Open()
    For Each row As DataRow In dt.Rows
          cmd.Parameters(0).Value = row(0)
          cmd.Parameters(1).Value = row(1)
          cmd.ExecuteNonQuery()
    Next
End Using

通常,对于任何 ADO.Net 提供程序,您都不会重复使用您的连接或命令对象。您希望每个发送到数据库的查询都有一个新的连接对象,以允许连接池正常工作。对同一个查询使用这样的紧密循环中的连接是少数例外之一。

我可以通过坚持使用活动的 DataReader 来进一步改进,而不是先将其加载到 DataTable 中。这将允许我们避免将整个结果集加载到内存中。您一次只需要一个记录在内存中。当然,这适用于 Sql Server。但是,Access 主要设计为单用户数据库。它真的不喜欢一次有多个活动连接,我不确定它会如何响应。

能够以事务方式完成所有这些工作也很好,在这种情况下,它永远不会在循环的一部分中失败并卡在一半的更新中。Sql Server 将通过单个 INSERT/SELECT 查询或显式事务处理此问题。但是,再一次,这不是 Access 的设计目的。它可能确实有办法做到这一点,但我不熟悉它。

于 2017-11-13T17:17:34.150 回答
0

好的,所以我终于找到了解决方法,这是一个漫长的过程,但基本上我将 SELECT 语句(具有多行)加载到 gridview 表中,并使用 for 循环将其插入到我的 insert into 语句中。下面是我的代码:

显示到表格中

    Dim Adapter As New OleDbDataAdapter
    Dim Data As New DataTable
    Dim SQL As String
    Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Shantara Production IT.mdb")
    Dim cmd As New OleDbCommand()
    grdvmachincomp.Visible = false
    SQL = "SELECT DISTINCT POH.BatchNo, SSCDD.ComponentID
                    FROM ([KN - ProductionOrderHeader] AS POH
                    INNER Join [FG - End Product Codes] AS EPC
                        On POH.ProductID = EPC.ProductID)
                    INNER Join([KN - ProductionOrderDetails] AS POD
                    INNER Join [FG - Style Size Comp Def Details]  AS SSCDD
                        On POD.SizeID = SSCDD.SizeID) 
                        On (POH.BatchNo = POD.BatchNo) 
                            And (EPC.StyleID = SSCDD.StyleID)
                    WHERE POH.BatchNo = '" & BatchNo & "'"
    con.Open()
    cmd.Connection = con
    cmd.CommandText = SQL

    Adapter.SelectCommand = cmd
    Adapter.Fill(Data)

    grdvmachincomp.DataSource = Data
    grdvmachincomp.DataBind()
    cmd.Connection.Close()

通过for循环插入

For c As Integer = 0 To grdvmachincomp.Rows.Count - 1
        Dim cmdstring As String
        cmdstring = " INSERT INTO [KN - ProductionMachineAllocation] (BatchNo, ComponentID) VALUES('" & grdvmachincomp.Rows(c).Cells(0).Text & "', " & grdvmachincomp.Rows(c).Cells(1).Text & ");"
        Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Shantara Production IT.mdb")
        Dim cmd As New OleDbCommand(cmdstring)
        cmd.CommandType = CommandType.Text
        cmd.Connection = con
        cmd.Connection.Open()
        cmd.ExecuteNonQuery()
        cmd.Connection.Close()
    Next
于 2017-11-13T16:17:02.083 回答