Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vba 使用ADODB中的十进制值执行查询时出现类型不匹配错误。参数类型为adNumeric_Vba_Excel_Ms Access_Adodb - Fatal编程技术网

Vba 使用ADODB中的十进制值执行查询时出现类型不匹配错误。参数类型为adNumeric

Vba 使用ADODB中的十进制值执行查询时出现类型不匹配错误。参数类型为adNumeric,vba,excel,ms-access,adodb,Vba,Excel,Ms Access,Adodb,我需要使用Excel VBA将一些数据从SQL Server表复制到类似的Access表。为此,我创建了一个函数,该函数基于对SQL Server的Select语句创建Insert SQL以访问DB(PreparedStatement) 字符串、日期和整数处理得很好。十进制值(adNumber类型)如何导致错误“条件表达式中的数据类型不匹配”。如果我将十进制值四舍五入为整数,事情就会顺利进行。我还确认可以使用access手动将十进制值输入到目标表中 原始SQL Server源表字段中的数据类型为

我需要使用Excel VBA将一些数据从SQL Server表复制到类似的Access表。为此,我创建了一个函数,该函数基于对SQL Server的Select语句创建Insert SQL以访问DB(PreparedStatement)

字符串、日期和整数处理得很好。十进制值(adNumber类型)如何导致错误“条件表达式中的数据类型不匹配”。如果我将十进制值四舍五入为整数,事情就会顺利进行。我还确认可以使用access手动将十进制值输入到目标表中

原始SQL Server源表字段中的数据类型为十进制(18,4),而目标访问表中的相应类型为数字(精度为18,刻度为4的十进制字段类型)。下面的代码将字段视为adNumeric类型,NumericScale为4,精度为18

例如,当我从源表中读取值5.16并尝试将其插入目标表时,我得到一个错误。如果我将读取值四舍五入为5,则插入操作不会出错

那么,我在这里做错了什么?我应该怎么做才能使十进制数正确

我根据select查询创建并执行insert语句,如下所示:

Private Sub AddToTargetDatabase(ByRef source As ADODB.Recordset, ByRef targetCn As ADODB.connection, tableName As String)
Dim flds As ADODB.Fields
Set flds = source.Fields
'target table is cleared at the beginning
targetCn.Execute ("DELETE FROM " & tableName)

Dim insertSQL As String
insertSQL = "INSERT INTO " & tableName & "("

Dim valuesPart As String
valuesPart = ") VALUES ("

Dim i As Integer

Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = targetCn
cmd.Prepared = True
Dim parameters() As ADODB.Parameter
ReDim parameters(flds.Count)

'Construct insert statement and parameters
For i = 0 To flds.Count - 1
    If (i > 0) Then
        insertSQL = insertSQL & ","
        valuesPart = valuesPart & ","
    End If
    insertSQL = insertSQL & "[" & flds(i).Name & "]"
    valuesPart = valuesPart & "?"
    Set parameters(i) = cmd.CreateParameter(flds(i).Name, flds(i).Type, adParamInput, flds(i).DefinedSize)
    parameters(i).NumericScale = flds(i).NumericScale
    parameters(i).Precision = flds(i).Precision
    parameters(i).size = flds(i).DefinedSize
    cmd.parameters.Append parameters(i)
Next i
insertSQL = insertSQL & valuesPart & ")"
Debug.Print insertSQL
cmd.CommandText = insertSQL

'String generated only for debug purposes
Dim params As String


Do Until source.EOF

    params = ""
    For i = 0 To flds.Count - 1
        Dim avalue As Variant


        If (parameters(i).Type = adNumeric) And Not IsNull(source.Fields(parameters(i).Name).Value) And parameters(i).Precision > 0 Then
            avalue = source.Fields(parameters(i).Name).Value
            'If rounded insert works quite nicely
            'avalue = Round(source.Fields(parameters(i).Name).Value)
        Else
            avalue = source.Fields(parameters(i).Name).Value
        End If

        'construct debug for the line
        params = params & parameters(i).Name & " (" & parameters(i).Type & "/" & parameters(i).Precision & "/" & source.Fields(parameters(i).Name).Precision & ") = " & avalue & "|"

        parameters(i).Value = avalue

    Next i
    'print debug line containing parameter info
    Debug.Print params
    'Not working with decimal values!!
    cmd.Execute
    source.MoveNext
Loop

End Sub

我想小数的问题是,在Excel中使用逗号作为十进制符号,而在Access中它是一个点。要检查此假设是否正确,请执行以下操作:

  • 单击文件>选项
  • 在“高级”选项卡上的“编辑选项”下,清除“使用系统分隔符”复选框
  • 在十进制分隔符和千位分隔符中键入新分隔符 分隔盒
然后再运行一次。如果它运行完美,那么这就是问题所在

编辑: 你能这样做吗:
replace(strValue,“,”,“)
在传递十进制值的位置解决问题?我想是这样的:

`insertSQL = insertSQL & "[" & replace(flds(i).Name,",",".") & "]"`

使用Str将小数转换为字符串表示形式以进行连接。Str始终为小数分隔符插入一个点

或者使用我的功能:

' Converts a value of any type to its string representation.
' The function can be concatenated into an SQL expression as is
' without any delimiters or leading/trailing white-space.
'
' Examples:
'   SQL = "Select * From TableTest Where [Amount]>" & CSql(12.5) & "And [DueDate]<" & CSql(Date) & ""
'   SQL -> Select * From TableTest Where [Amount]> 12.5 And [DueDate]< #2016/01/30 00:00:00#
'
'   SQL = "Insert Into TableTest ( [Street] ) Values (" & CSql(" ") & ")"
'   SQL -> Insert Into TableTest ( [Street] ) Values ( Null )
'
' Trims text variables for leading/trailing Space and secures single quotes.
' Replaces zero length strings with Null.
' Formats date/time variables as safe string expressions.
' Uses Str to format decimal values to string expressions.
' Returns Null for values that cannot be expressed with a string expression.
'
' 2016-01-30. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function CSql( _
    ByVal Value As Variant) _
    As String

    Const vbLongLong    As Integer = 20
    Const SqlNull       As String = " Null"

    Dim Sql             As String
    Dim LongLong        As Integer

    #If Win32 Then
        LongLong = vbLongLong
    #End If
    #If Win64 Then
        LongLong = VBA.vbLongLong
    #End If

    Select Case VarType(Value)
        Case vbEmpty            '    0  Empty (uninitialized).
            Sql = SqlNull
        Case vbNull             '    1  Null (no valid data).
            Sql = SqlNull
        Case vbInteger          '    2  Integer.
            Sql = Str(Value)
        Case vbLong             '    3  Long integer.
            Sql = Str(Value)
        Case vbSingle           '    4  Single-precision floating-point number.
            Sql = Str(Value)
        Case vbDouble           '    5  Double-precision floating-point number.
            Sql = Str(Value)
        Case vbCurrency         '    6  Currency.
            Sql = Str(Value)
        Case vbDate             '    7  Date.
            Sql = Format(Value, " \#yyyy\/mm\/dd hh\:nn\:ss\#")
        Case vbString           '    8  String.
            Sql = Replace(Trim(Value), "'", "''")
            If Sql = "" Then
                Sql = SqlNull
            Else
                Sql = " '" & Sql & "'"
            End If
        Case vbObject           '    9  Object.
            Sql = SqlNull
        Case vbError            '   10  Error.
            Sql = SqlNull
        Case vbBoolean          '   11  Boolean.
            Sql = Str(Abs(Value))
        Case vbVariant          '   12  Variant (used only with arrays of variants).
            Sql = SqlNull
        Case vbDataObject       '   13  A data access object.
            Sql = SqlNull
        Case vbDecimal          '   14  Decimal.
            Sql = Str(Value)
        Case vbByte             '   17  Byte.
            Sql = Str(Value)
        Case LongLong           '   20  LongLong integer (Valid on 64-bit platforms only).
            Sql = Str(Value)
        Case vbUserDefinedType  '   36  Variants that contain user-defined types.
            Sql = SqlNull
        Case vbArray            ' 8192  Array.
            Sql = SqlNull
        Case Else               '       Should not happen.
            Sql = SqlNull
    End Select

    CSql = Sql & " "

End Function
”将任何类型的值转换为其字符串表示形式。
'该函数可以按原样连接到SQL表达式中
'没有任何分隔符或前导/尾随空格。
'
例如:

'SQL=“Select*From TableTest Where[Amount]>”&CSql(12.5)&“和[DueDate]在经过几个小时的反复试验后,我找到了解决方案,回答了我自己的问题

在SQL Server的Select语句的adNumeric类型精度大于0的情况下,我似乎需要更改参数字段类型。将目标Access DB查询参数类型更改为adDouble而不是adDecimal或adNumber可以达到以下目的:

    Dim fieldType As Integer
    If (flds(i).Type = adNumeric And flds(i).Precision > 0) Then
        fieldType = adDouble
    Else
        fieldType = flds(i).Type
    End If
    Set parameters(i) = cmd.CreateParameter("@" & flds(i).Name, fieldType, adParamInput, flds(i).DefinedSize)

我曾经处理过类似的案件,我按照以下步骤解决了。对不起,我的英语不好,我会尽力做到最好:)

我已经创建了一个临时excel工作表,所有列的名称都像第一行中的sql表。当主工作表中的主表使用
=SI($B2=“”;”;MainSheet!$F15)
=SI($B2=“”;”;TEXTO(Fecha;“yyy-DD-MM HH:MM:ss.mss”)等公式填充时,该表中的数据将自动填充
在日期时间值的情况下。在数字的情况下
=SI($B2=“”;VALOR(十进制(MainSheet!AB15;2))

在那之后,我将@Gustav附加到模块上,只需稍加修改即可从单元格的值中读取“NULL”以转义引号

    ' Converts a value of any type to its string representation.
' The function can be concatenated into an SQL expression as is
' without any delimiters or leading/trailing white-space.
'
' Examples:
'   SQL = "Select * From TableTest Where [Amount]>" & CSql(12.5) & "And [DueDate]<" & CSql(Date) & ""
'   SQL -> Select * From TableTest Where [Amount]> 12.5 And [DueDate]< #2016/01/30 00:00:00#
'
'   SQL = "Insert Into TableTest ( [Street] ) Values (" & CSql(" ") & ")"
'   SQL -> Insert Into TableTest ( [Street] ) Values ( Null )
'
' Trims text variables for leading/trailing Space and secures single quotes.
' Replaces zero length strings with Null.
' Formats date/time variables as safe string expressions.
' Uses Str to format decimal values to string expressions.
' Returns Null for values that cannot be expressed with a string expression.
'
' 2016-01-30. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function CSql( _
    ByVal Value As Variant) _
    As String

    Const vbLongLong    As Integer = 20
    Const SqlNull       As String = " Null"

    Dim Sql             As String
    'Dim LongLong        As Integer

    #If Win32 Then
    '    LongLong = vbLongLong
    #End If
    #If Win64 Then
    '    LongLong = VBA.vbLongLong
    #End If

    Select Case VarType(Value)
        Case vbEmpty            '    0  Empty (uninitialized).
            Sql = SqlNull
        Case vbNull             '    1  Null (no valid data).
            Sql = SqlNull
        Case vbInteger          '    2  Integer.
            Sql = Str(Value)
        Case vbLong             '    3  Long integer.
            Sql = Str(Value)
        Case vbSingle           '    4  Single-precision floating-point number.
            Sql = Str(Value)
        Case vbDouble           '    5  Double-precision floating-point number.
            Sql = Str(Value)
        Case vbCurrency         '    6  Currency.
            Sql = Str(Value)
        Case vbDate             '    7  Date.
            Sql = Format(Value, " \#yyyy\/mm\/dd hh\:nn\:ss\#")
        Case vbString           '    8  String.
            Sql = Replace(Trim(Value), "'", "''")
            If Sql = "" Then
                Sql = SqlNull
            ElseIf Sql = "NULL" Then
                Sql = SqlNull
            Else
                Sql = " '" & Sql & "'"
            End If
        Case vbObject           '    9  Object.
            Sql = SqlNull
        Case vbError            '   10  Error.
            Sql = SqlNull
        Case vbBoolean          '   11  Boolean.
            Sql = Str(Abs(Value))
        Case vbVariant          '   12  Variant (used only with arrays of variants).
            Sql = SqlNull
        Case vbDataObject       '   13  A data access object.
            Sql = SqlNull
        Case vbDecimal          '   14  Decimal.
            Sql = Str(Value)
        Case vbByte             '   17  Byte.
            Sql = Str(Value)
        'Case LongLong           '   20  LongLong integer (Valid on 64-bit platforms only).
            Sql = Str(Value)
        Case vbUserDefinedType  '   36  Variants that contain user-defined types.
            Sql = SqlNull
        Case vbArray            ' 8192  Array.
            Sql = SqlNull
        Case Else               '       Should not happen.
            Sql = SqlNull
    End Select

    CSql = Sql & " "

End Function
CellValue=CSql(rangeCell.Value)

我在临时工作表中添加了最后一列,
=SI(A2“;Insert2DB(A2:W2;$a$1:$W$1;“sql_table”);”)

在我运行以导出到SQL的宏中

With Sheets("tempSheet")



' Column where Insert2DB formula is

Excel_SQLQuery_Column = "X"

'Skip the header row
iRowNo = 2

'Loop until empty cell
Do Until .Cells(iRowNo, 1) = ""



    iRowAddr = Excel_SQLQuery_Column & iRowNo

    SQLstr = .Range(iRowAddr).Value

    Cn.Execute (SQLstr)

    iRowNo = iRowNo + 1

Loop

End With

这对我很有用。谢谢@Gustav和@Petrik分享他的代码。

让我猜一下……您的十进制符号是逗号?在DB中是
?我的系统十进制分隔符是逗号,正如您所怀疑的。我没有选中“使用系统分隔符”复选框,但它没有解决问题。为了安全起见,我还添加了代码块应用程序。小数分隔符=“”。“Application.UseSystemSeparators=在程序开始时为False,功能没有任何更改。“调试打印输出”仍然使用逗号格式化小数,所以可能我遗漏了什么?@Jupe-请参阅编辑。您没有错过,VBE编辑器有点奇怪。即使您在编辑器中写入
k=4.5
,然后用
?k
打印,也会用逗号显示。您在编辑中所指的行仅包含字段名,不包含值。我使用的是preparedStatements,因此实际的插入类似于插入tableName(fieldName1,fieldName2)值(?),该值在显示parameters(I)的行中设置为parameter。value=avalue我确实尝试在那里更改小数分隔符,但这表明我使用的字符串会导致另一个错误:“应用程序使用了错误类型的值…”,因为参数定义为adNumeric类型。感谢您的建议。在这种情况下,将值转换为字符串没有帮助,因为命令对象的参数需要数值。我最终通过将参数类型改为adDouble而不是adNumeric来解决此问题。
With Sheets("tempSheet")



' Column where Insert2DB formula is

Excel_SQLQuery_Column = "X"

'Skip the header row
iRowNo = 2

'Loop until empty cell
Do Until .Cells(iRowNo, 1) = ""



    iRowAddr = Excel_SQLQuery_Column & iRowNo

    SQLstr = .Range(iRowAddr).Value

    Cn.Execute (SQLstr)

    iRowNo = iRowNo + 1

Loop

End With