【问题标题】:insert multiple rows with one query using ms access db使用 ms access db 通过一个查询插入多行
【发布时间】:2018-04-26 03:55:59
【问题描述】:

我试图将多行放入一个表中,因此我尝试获取行号并将其放入 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 访问不支持通过插入到我的 select 语句中插入多行,关于我的问题的任何建议?

【问题讨论】:

标签: asp.net vb.net ms-access oledb insert-select


【解决方案1】:

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

GridView 是视觉结构,会消耗额外的内存和资源。如果 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 的设计目的。它可能确实有办法做到这一点,但我不熟悉它。

【讨论】:

  • @Joel_Coehoorn 非常感谢......所以我使用 ms 访问的原因是因为当前系统是建立在 access(vba) 上的所有形式,所以我慢慢将表单移植到这个新的 asp.net 应用程序,一旦移植了整个系统,我将使用升迁向导将整个 db 移植到 sql server。但是,是的,我同意你的观点,即访问不适合多用户,因为系统时不时会崩溃并显示“未确定的错误”消息,我认为这是连接池队列中连接字符串的过载
【解决方案2】:

好的,所以我终于找到了解决方法,这是一个漫长的过程,但基本上我将 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

【讨论】:

  • 这仍然很容易受到 sql 注入攻击。如果有人设法在批号中创建一个带有单引号的批次,上帝会帮助你。
  • @JoelCoehoorn 我很清楚用于防止 sql 注入的 cmd.Parameters.Add( ) 我只是懒得把它放进去。这个程序也仅供内部使用无法访问系统其余部分的人(除了他们忙于处理的表格)是未受过教育的地勤人员机器操作员。感谢您的提醒
  • @JoelCoehoorn 也是,你的看起来确实不错,唯一的原因是我的绿色打勾是因为我的对我有用,而我没有尝试过你的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-06
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
相关资源
最近更新 更多