[英]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 个工作表:
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/Collate-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.