【问题标题】:Runtime error 3001 'Arguments are of the wrong type or out of acceptable range...'运行时错误 3001 '参数类型错误或超出可接受范围...'
【发布时间】:2015-11-17 20:55:41
【问题描述】:

我有一个 Excel 表,想更新 Excel 第 12 列引用的 SQL Server 表记录的日期值(使用 getdate 函数)。

我的代码如下,但我看到了:

运行时错误 3001 参数类型错误或超出可接受范围或相互冲突。

SQL表中MODIFIEDDATE字段为日期时间类型,MAINREF字段为整数类型。

Private Sub CommandButton2_Click()

Dim conn2 As New ADODB.Connection
Dim rst2 As New ADODB.Recordset
Dim j As Integer

conn2.ConnectionString = "Provider=SQLOLEDB.1;Password=abc;Persist Security Info=True;User ID=sa;Initial Catalog=logodb;Data Source=A3650;Use Procedure for Prepare=1;Auto"
conn2.Open

For j = 0 To 1900
    If Sayfa1.Cells(j + 4, 12) = "" Then
        Sayfa1.Cells(j + 4, 13) = "empty"
    Else
        rst2.Open "UPDATE T_015 SET MODIFIEDDATE=GETDATE() WHERE MAINREF='" & Sayfa1.Cells(j + 4, 12) & "'", conn, 1, 3
        rst2.Close
    End If
Next j

End Sub

我尝试更改 SQL 查询,例如 (CInt(cell.value))

rst2.Open "UPDATE T_015 SET MODIFIEDDATE=GETDATE() WHERE MAINREF='" & CInt(Sayfa1.Cells(j + 4, 12)) & "'", conn, 1, 3

但是,它没有用。

【问题讨论】:

  • 如果MAINREF 是数字,为什么要将它与表示数字的字符串进行比较?不应该是... WHERE MAINREF=" & Sayfa1.Cells(j + 4, 12) 吗?
  • 你说得对,我已经改变了 ...WHERE MAINPRODREF=" & Sayfa1.Cells(j + 4, 12) & "", conn2, 1, 3 但这次我我看到“参数数量错误或属性分配无效” 消息。

标签: sql-server vba excel


【解决方案1】:

ADODB.Recordset 对象不应用于 UPDATE 查询。直接从 ADODB.Connection 执行 SQL 语句

Dim conn2 As New ADODB.Connection

conn2.ConnectionString = "Provider=SQLNCLI11;Server=MYSERVER;Database=TMP;UID=sa;password=abc;"
conn2.Open

conn2.Execute "UPDATE T_015 SET MODIFIEDDATE=GETDATE() WHERE MAINREF=1"

【讨论】:

  • 当我像你提供的那样改变时,它会导致“参数数量错误或属性分配无效”消息
  • 抱歉,我将..., conn, 1, 3 留在了右端。它应该已被删除。 (顺便说一句,在您的问题代码中,conn 不是 conn2
  • 我意识到,在问这个问题之前,我编辑了它,但错误信息是一样的。
  • conn2.Execute "UPDATE T_015 SET MODIFIEDDATE=GETDATE() WHERE MAINREF=" & Sayfa1.Cells(j + 4, 12) & "", conn2, 1, 3 > 只是更改了这一行。错误消息用黄色“Private Sub ...”表示代码的第一行
  • 我将连接字符串更改为我更熟悉的字符串,并运行了一个“简化”版本。我在 MYSERVER 机器上的 TMP 数据库中构建的 T_015 表快速运行,没有问题。
【解决方案2】:

有几种方法可以满足您的要求,而且您似乎正在混合使用这两种方法。

一种方法是一次更新一条记录,为此您可以使用Connection 对象,或者更优选的是Command 对象。我说最好是因为参数化命令是执行 SQL 的一种更健壮的方式。如果您打算使用 SQL,那么您可能应该阅读它。你会这样做的方式如下:

Public Sub ParameterisedProcedure()
    Dim conn As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim prm As ADODB.Parameter
    Dim v As Variant
    Dim j As Integer

    'Read the sheet data
    v = Sayfa1.Range("L4", "M1904").Value2

    'Open the database connection
    Set conn = New ADODB.Connection
    conn.ConnectionString = "Provider=SQLOLEDB.1;" & _
                              "Password=abc;" & _
                              "Persist Security Info=True;" & _
                              "User ID=sa;" & _
                              "Initial Catalog=logodb;" & _
                              "Data Source=A3650;" & _
                              "Use Procedure for Prepare=1;" & _
                              "Auto"
    conn.Open

    'Loop through the values to update records
    For j = 1 To UBound(v, 1)
        If IsEmpty(v(j, 1)) Then
            v(j, 2) = "empty"
        Else
            'Create the parameterised command
            Set cmd = New ADODB.Command
            cmd.ActiveConnection = conn
            cmd.CommandType = adCmdText
            cmd.CommandText = "UPDATE T_015 " & _
                              "SET MODIFIEDDATE=? " & _
                              "WHERE MAINREF=?"
            prm = cmd.CreateParameter(Type:=adDate, Value:=Now)
            cmd.Parameters.Append prm
            prm = cmd.CreateParameter(Type:=adInteger, Value:=v(j, 1))
            cmd.Parameters.Append prm
            cmd.Execute
        End If
    Next

    'Write the updated values
    Sayfa1.Range("L4", "M1904").Value = v

    'Close the database
    Set prm = Nothing
    Set cmd = Nothing
    conn.Close

End Sub

另一种方法是使用Transactions,您确实会为此使用Recordset(即类似于您已经完成的操作)。在这种情况下,我建议这是更好的方法,因为一次执行一个命令(如上面的代码)非常慢。一种更快的方法是在一个事务中提交所有更新。与参数化命令一样,它也可以防止恶意字符串进入您的 SQL 命令文本。代码如下所示:

Public Sub TransactionProcedure()
    Dim conn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim cmdText As String
    Dim v As Variant
    Dim j As Integer

    'Read the sheet data
    v = Sayfa1.Range("L4", "M1904").Value2

    'Open the database connection
    Set conn = New ADODB.Connection
    conn.ConnectionString = "Provider=SQLOLEDB.1;" & _
                              "Password=abc;" & _
                              "Persist Security Info=True;" & _
                              "User ID=sa;" & _
                              "Initial Catalog=logodb;" & _
                              "Data Source=A3650;" & _
                              "Use Procedure for Prepare=1;" & _
                              "Auto"
    conn.Open

    'Retrieve the data
    Set rs = New ADODB.Recordset
    cmdText = "SELECT * FROM  T_015"
    rs.Open cmdText, conn, adOpenStatic, adLockReadOnly, adCmdText

    'Loop through the values to update the recordset
    On Error GoTo EH
    conn.BeginTrans
    For j = 1 To UBound(v, 1)
        If IsEmpty(v(j, 1)) Then
            v(j, 2) = "empty"
        Else
            'Find and update the record
            rs.Find "MAINREF=" & CStr(v(j, 1))
            If Not rs.EOF Then
                rs!ModifiedDate = Now
                rs.Update
            End If
        End If
    Next
    conn.CommitTrans

    'Write the updated values
    Sayfa1.Range("L4", "M1904").Value = v

    'Close the database
    rs.Close
    conn.Close
    Exit Sub

EH:
    conn.RollbackTrans
    Sayfa1.Range("L4", "M1904").Value = v
    rs.Close
    conn.Close
    MsgBox Err.Description
End Sub

【讨论】:

    猜你喜欢
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    相关资源
    最近更新 更多