简体   繁体   English

ADO (Excel, ACE OLEDB 12.0) 不比较 Key-Strings 区分大小写

[英]ADO (Excel, ACE OLEDB 12.0) does not compare Key-Strings case-sensitive

Problem Description: When Joining 2 Tables using Excel and ADO (ACE OLEDB 12.0) on alphanumeric Strings, ADO does not distinguish between the Keys "a12a" and "A12a" (it treats them as if they would be the same, ie case-insensitive).问题描述:在字母数字字符串上使用 Excel 和 ADO (ACE OLEDB 12.0) 连接 2 个表时,ADO 不区分键“a12a”和“A12a”(它将它们视为相同,即不区分大小写)。 I, however, have alphanumeric keys in my data.但是,我的数据中有字母数字键。 The Join will link the data wrongly! Join 将错误地链接数据!

I built a small example in an Excel Workbook to reproduce the behavior.我在 Excel 工作簿中构建了一个小示例来重现该行为。 The Excel Workbook contains 3 Sheets: Excel 工作簿包含 3 个工作表:

  1. AlphaNum1字母数字 1
  2. AlphaNum2字母数字 2
  3. Result结果

AlphaNum1 Sheet contains the following data AlphaNum1 表包含以下数据

Key   Val
a12b    1
A12b    2
a12B    3
A12B    4
e12f    7
E12F    8
1234    9

AlphaNum2 Sheet contains the following data: AlphaNum2 表包含以下数据:

Key   Val
a12b    1
A12b    2
a12B    3
A12B    4
c12d    5
C12D    6
1234    9

I Use the following VBA code to connect to ADO and join the tables (LEFT JOIN):我使用以下 VBA 代码连接到 ADO 并加入表(LEFT JOIN):

Sub AlphaNumTest()
    Dim oAdoConnection As New ADODB.Connection
    Dim oAdoRecordset As New ADODB.Recordset
    Dim sAdoConnectString As String, sPfad As String
    Dim sQuery As String
    On Error GoTo ExceptionHandling
    sPfad = ThisWorkbook.FullName
    sAdoConnectString = "Provider=Microsoft.ACE.OLEDB.12.0; Extended Properties='Excel 12.0 Xml;HDR=YES;';Data Source=" & sPfad

    oAdoConnection.Open sAdoConnectString
    sQuery = "Select a1.[Key], a2.[Val] from [AlphaNum1$] a1 LEFT JOIN [AlphaNum2$] a2 ON a1.[Key] = a2.[Key]"
    With oAdoRecordset
        .Source = sQuery
        .ActiveConnection = oAdoConnection
        .Open
    End With

    Dim writeRange As Range
    Dim headerRange As Range

    'Set headerRange = ThisWorkbook.Sheets("WriteHere").Range("A1")
    Set writeRange = ThisWorkbook.Sheets("Result").Range("A2")

    ' print the table header from recordset
    For i = 0 To oAdoRecordset.Fields.Count - 1
        ' careful! the recordset is zero-indexed like it should be! Excel table however starts at index one, thus the i+1~
        ThisWorkbook.Sheets("Result").Cells(1, i + 1).Value = oAdoRecordset.Fields(i).Name
        ' set bold
        ThisWorkbook.Sheets("Result").Cells(1, i + 1).Font.Bold = True
    Next i

    ' print the data directly from recordset!
    writeRange.CopyFromRecordset oAdoRecordset


CleanUp:
    On Error Resume Next ' Lazy skip
    oAdoRecordset.Close
    oAdoConnection.Close
    Set oAdoRecordset = Nothing
    Set oAdoConnection = Nothing
    Exit Sub
ExceptionHandling:
    MsgBox "Fehler: " & Err.Description
    Resume CleanUp
End Sub

Note that it does not matter if I use an INNER or a LEFT JOIN;请注意,我使用 INNER 或 LEFT JOIN 并不重要; the result is wrong eiter way - in this example here I use a LEFT JOIN to demonstrate the behavior.无论哪种方式,结果都是错误的 - 在此示例中,我使用 LEFT JOIN 来演示该行为。

The Result output is AlphaNum1.Key and AlphaNum2.Val joined by LEFT JOIN.结果输出是 AlphaNum1.Key 和 AlphaNum2.Val 由 LEFT JOIN 连接。

The Expected Result (I am joining using "=" not LIKE...) is:预期结果(我加入使用“=”而不是 LIKE...)是:

Key   Val
a12b    1
A12b    2
a12B    3
A12B    4
e12f    
E12F    
1234    9

But ADO gives me the Actual Result (it treats the Keys case insensitive...):但是 ADO 给了我实际结果(它不区分大小写的键...):

Key   Val
a12b    4
a12b    3
a12b    2
a12b    1
A12b    4
A12b    3
A12b    2
A12b    1
a12B    4
a12B    3
a12B    2
a12B    1
A12B    4
A12B    3
A12B    2
A12B    1
e12f    
E12F    
1234    9

Any ideas why ADO behaves like this?任何想法为什么 ADO 会这样? Any ideas how/if I can change the behavior?任何想法如何/如果我可以改变行为?

I found a workaround for ADO.我找到了 ADO 的解决方法。 Seems COLLATE does not exist (see: http://www.utteraccess.com/forum/Collate-Access-t1940463.html ).似乎COLLATE不存在(参见: http : //www.utteraccess.com/forum/Collat​​e-Access-t1940463.html )。

One can use StrComp and set it to binary compare:可以使用 StrComp并将其设置为二进制比较:

sQuery = "Select a1.[Key], a2.[Val] from [AlphaNum1$] a1 LEFT JOIN [AlphaNum2$] a2 **ON StrComp(a1.[Key], a2.[Key], 0)=0**"

If there is a better solution I am happy for more suggestions :)如果有更好的解决方案,我很乐意提供更多建议:)

You could add a new indexed text field to each table, then fill this with values using the function below, and then join the tables the normal way using these fields:您可以向每个表添加一个新的索引文本字段,然后使用下面的函数用值填充它,然后使用这些字段以正常方式连接表:

Public Function StrToByte(ByVal strChars As String) As String

  Dim abytChar()  As Byte
  Dim lngChar     As Long
  Dim strByte     As String

  abytChar() = StrConv(strChars, vbFromUnicode)

  strByte = Space(2 * (1 + UBound(abytChar) - LBound(abytChar)))
  For lngChar = LBound(abytChar) To UBound(abytChar)
    Mid(strByte, 1 + 2 * lngChar) = Hex(abytChar(lngChar))
  Next

  StrToByte = strByte

End Function

It will produce keys like:它将产生如下键:

StrToByte("a12b") -> 61313262
StrToByte("A12b") -> 41313262

Just to report that i have reproduced your example, and got the 'Expected Result' at first time, without any modification in your code只是为了报告我已经复制了您的示例,并在第一时间获得了“预期结果”,而没有对您的代码进行任何修改

I'm using Excel 2007 and ADO 2.8我使用的是 Excel 2007 和 ADO 2.8

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM