使用 ms access db 通过一个查询插入多行
insert multiple rows with one query using ms access db
我试图将多行放入 table 因此我尝试获取行号并将其放入 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 access 不支持 ROW_NUMBER()
所以我需要找到另一个遍历每一行,因为 ms access 不支持通过插入 select 语句这样的多行插入作为我的,对我的问题有什么建议吗?
好的,所以我终于找到了解决方法,这是一个漫长的过程,但基本上我将 SELECT 语句(多行)加载到 gridview table 中并使用了for 循环将其插入到我的 insert into 语句中。下面是我的代码:
显示成 table
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 服务器中,我可以将整个事情归结为一个查询。 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 服务器。但是,Access 主要设计为单用户数据库。它不太喜欢一次有多个活动连接,我不确定它会如何响应。
能够以事务方式完成所有这些工作也很好,这样就不会存在在循环中途失败并卡在一半更新中的任何风险。 Sql 服务器将通过单个 INSERT/SELECT 查询或显式事务来处理此问题。但是,这不是 Access 设计的目的。它可能确实有办法做到这一点,但我不熟悉它。
我试图将多行放入 table 因此我尝试获取行号并将其放入 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 access 不支持 ROW_NUMBER()
所以我需要找到另一个遍历每一行,因为 ms access 不支持通过插入 select 语句这样的多行插入作为我的,对我的问题有什么建议吗?
好的,所以我终于找到了解决方法,这是一个漫长的过程,但基本上我将 SELECT 语句(多行)加载到 gridview table 中并使用了for 循环将其插入到我的 insert into 语句中。下面是我的代码:
显示成 table
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 服务器中,我可以将整个事情归结为一个查询。 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 服务器。但是,Access 主要设计为单用户数据库。它不太喜欢一次有多个活动连接,我不确定它会如何响应。
能够以事务方式完成所有这些工作也很好,这样就不会存在在循环中途失败并卡在一半更新中的任何风险。 Sql 服务器将通过单个 INSERT/SELECT 查询或显式事务来处理此问题。但是,这不是 Access 设计的目的。它可能确实有办法做到这一点,但我不熟悉它。