将 table rrecordset 传递到 SQL 服务器

Passing a table rrecordset to SQL server

各位专家下午好!

我遇到了一种与平时截然不同的问题。过去我通过 'Pass through Query' 向服务器传递单行,有时当我需要传递多条记录时,我利用循环函数多次将数据发送到服务器。但是,如果我有超过 40 行记录,则该循环将花费大量时间才能完成。我只是想知道是否有一种方法可以在 1 次移动中将 table 集发送到服务器,而不是使用循环的 X 次移动。

这是我在附加到表单内按钮的访问端使用的代码(记录源是本地访问 table):

Dim db As dao.Database
Dim rs As dao.Recordset
Dim qdf As dao.QueryDef
Dim strSQL As String

Set db = CurrentDb
Set rs = Me.Recordset

rs.MoveLast
rs.MoveFirst

Do While Not rs.EOF
Set qdf = db.QueryDefs("Qry_Send_ClientData") 'local pass through query

strSQL = "EXEC dbo.SP_Client_Referral @JunctionID='" & Me.ClientID & "', @Note='" & Replace(Me.Txt_Note, "'", "") & "', @Value1='" & Txt_Value1 & "', @Value2='" & Txt_Value2 & "'"

qdf.SQL = strSQL
db.Execute "Qry_Send_ClientData"

rs.MoveNext
Loop

Msgbox "All Client Added!", , "Add client"

现在,在 SQL 服务器端,我有以下存储过程 (dbo.SP_Client_Referral),它从传递查询接收数据并将代码行插入到特定 table

    @ClientID AS NVARCHAR(15),
    @Note As NVARCHAR(500),
    @Value1 As NVARCHAR(50),
    @Value2 As NVARCHAR(50)
AS  

BEGIN

    SET NOCOUNT ON;

        BEGIN
        INSERT INTO dbo.Client_Data(ClientID, Note, Value_1, Value_2)
        SELECT @ClientID, @Note, @Value1, @Value2
        END

END

对于单条记录甚至最多10条记录这种方法是比较快的。然而,随着记录数量的增加,所需的时间可能会很长。如果有一种方法可以将 table(即使用 SELECT * 来自 LocalTable 的访问端)传递给 SQL 服务器,而不是逐行传递,肯定会节省很多时间。只是想知道这种方法是否存在,如果存在,我将如何发送 table 以及我必须在 SP 的 SQL 服务器端使用什么来接收 table 记录。或者,我可能不得不继续使用这种单行方法,并可能提高它的效率,以便它执行得更快。

非常感谢您的帮助!

您可以尝试将 XML 数据传递给存储过程。

DECLARE @rowData XML

SELECT @rowData = '<data><record clientid="01" Notes="somenotes" Value1="val1" Value2="val2" /><record clientid="02" Notes="somenotes 2" Value1="val1-2" Value2="val2-2" /></data>'

SELECT X.custom.value('@clientid', 'varchar(max)'),
    X.custom.value('@Notes', 'varchar(max)'),
    X.custom.value('@Value1', 'varchar(max)'),
    X.custom.value('@Value2', 'varchar(max)')
FROM @rowData.nodes('/data/record') X(custom)

实际上,最快的方法是什么?

好吧,这似乎非常违反直觉,我可以给出很长的解释来解释原因。然而,试试这个,你会发现它 运行s 是你现在拥有的 10 倍或更好。事实上,它很可能比你拥有的更接近 100 倍。

我们假设我们有一个标准的 linked 故事到 dbo.Client_Data。 link 可能是 Client_Data,甚至 dbo_Cliet_Data

所以,使用这个:

Dim rs      As DAO.Recordset
Dim rsIns   As DAO.Recordset

If Me.Dirty = True Then Me.Dirty = False  ' write any pending data

Set rsIns = CurrentDb.OpenRecordset("dbo_Client_Data", dbOpenDynaset, dbSeeChanges)

Set rs = Me.RecordsetClone
rs.MoveFirst

Do While Not rs.EOF
   With rsIns
      .AddNew
      !ClientID = rs!ClientID
      !Note = Me.Txt_Note
      !Value_1 = Me.Txt_Value1
      !Value_2 = Me.Txt_Value2
      .Update
   End With

   rs.MoveNext
Loop
rsIns.Close
MsgBox "All Client Added!", , "Add client"

注意上面的一些奖金。我们的代码很干净——我们不必担心数据类型,例如日期,或您乱七八糟的报价问题。如果涉及日期,我们可以再次分配而不必担心分隔符。我们还有开机注入保护的加成!

我们也使用了me.RecordSetClone。这不是必须做的。这将有助于提高性能,但最重要的是当您移动记录指针时,表单记录位置不会尝试跟随。这将消除很多潜在的闪烁。如果该表单上存在当前事件,它还可以消除巨大的问题。

因此,虽然这是一个非常好的主意 (recordsetclone),但它并不是您将在此处看到的性能大幅提升的主要原因。 RecordSetCloneme.RecordSet 相同,但您可以 "move" 并遍历记录集而无需跟随主窗体。

所以,实际上,最 "basic" 的代码方法,以及一种可以在没有 SQL 服务器的情况下进行访问的方法,结果证明是最好的方法。它的代码更少,混乱的代码更少,并且会为您省去设置 + 构建 SQL 服务器存储过程的所有麻烦。您所有的概念都不是必需的,更糟糕​​的是它们会导致性能下降。试试上面的概念。

Access 将批量处理并一次性管理多个插入。与 reocrdsets 相比,始终使用 SQL update/insert 命令的概念和想法是一个非常巨大的城市神话,许多访问开发人员都为之倾倒。这不是真的。真正的问题是,如果您可以用一个 SQL 更新语句替换大量单独执行的更新的 VBA 循环,那么是的,您遥遥领先(使用一个 SQL 更新一些 VBA 循环)。

但是,如果你必须做多个操作并且每个操作都在一行上?代替 "many separate" SQL 更新,那么在这种情况下,(是)绝大多数情况下,记录集将 运行 环绕一大堆单独的 update/insert 命令来实现相同的目标。它甚至还差得远,通过使用上述概念,您可以获得 10 倍甚至 100 倍的性能提升。