RODBC 从具有非标准名称的 Access 读取 table

RODBC read table from Access with non-standard name

我正在使用 R 处理 MS Access 中提供的数据集。当我努力使我的代码可重现时,我想避免使用 Access 对数据做任何事情。

数据库中有一些 table 具有非 ascii 字符(波斯语名称)

我连接到数据库:

cns <- odbcConnectAccess2007(mdbfilename)

当我得到 table 的列表时:

tbls <- sqlTables(cns)
head(tbls ,10) 

我得到这样的结果:

                   TABLE_CAT TABLE_SCHEM                 TABLE_NAME   TABLE_TYPE REMARKS
1  D:\HEIS\DataRAW\80.mdb        <NA>          MSysAccessObjects SYSTEM TABLE    <NA>
2  D:\HEIS\DataRAW\80.mdb        <NA>                   MSysACEs SYSTEM TABLE    <NA>
3  D:\HEIS\DataRAW\80.mdb        <NA> MSysNavPaneGroupCategories SYSTEM TABLE    <NA>
4  D:\HEIS\DataRAW\80.mdb        <NA>          MSysNavPaneGroups SYSTEM TABLE    <NA>
5  D:\HEIS\DataRAW\80.mdb        <NA>  MSysNavPaneGroupToObjects SYSTEM TABLE    <NA>
6  D:\HEIS\DataRAW\80.mdb        <NA>       MSysNavPaneObjectIDs SYSTEM TABLE    <NA>
7  D:\HEIS\DataRAW\80.mdb        <NA>                MSysObjects SYSTEM TABLE    <NA>
8  D:\HEIS\DataRAW\80.mdb        <NA>                MSysQueries SYSTEM TABLE    <NA>
9  D:\HEIS\DataRAW\80.mdb        <NA>          MSysRelationships SYSTEM TABLE    <NA>
10 D:\HEIS\DataRAW\80.mdb        <NA>    R80P1 روستا?? 80 بخش ?ک        TABLE    <NA>

如您所见,第 10 行 table 的名称包含非标准字符。 在 MS-Access 中显示的 table 的名称是 R80P1 روستایی 80 بخش یک。因为 MS-Access 尝试在系统的语言环境(波斯语)中发送名称,所以它会将数据转换为 Windows-阿拉伯语编码(代码页 1256),其中不包含波斯语 Yeh (ی) 的代码(与阿拉伯语 Yeh (ي) 不同)。

这使得无法从 R 中读取此 table 中的数据,因为我们确实没有名称:

tbl <- tbls[10,3]
RD <- sqlQuery(cns,paste0("Select Address from ",tbl))
head(RD)

我收到这个错误:

[1] "07002 17 [Microsoft][ODBC Microsoft Access Driver]COUNT field incorrect "            
[2] "[RODBC] ERROR: Could not SQLExecDirect 'Select Address from R80P1 روستا?? 80 بخش ?ک'"

我试过各种方法解决这个问题

  1. 在 MS-Access 中重命名 tables,因为我的脚本将从互联网上下载 30 多个文件,提取它们并阅读它们,这似乎不适合为其中一个文件进行手动重命名文件(有这个奇怪的命名)在过程中。
  2. 打开连接时更改编码,我已经尝试使用 iconvlist() 提供的所有 374 种编码,但没有解决问题。一个重要的案例:使用 UTF-8 打开 ODBC 连接导致有问题的 table 名称作为 NA.
  3. 返回
  4. 尝试不按名称而是按数据库中的索引来读取 table,但我不知道如何使用 RODBC 来读取 table(我通过 grepling 初始部分知道索引拉丁文名称)
  5. 尝试将 sqlFetch() 与自定义 SQL 查询一起使用,该查询在 table 名称上使用正则表达式,我不知道该怎么做,甚至不知道这是否可行。

有什么建议吗?

编辑: 我必须添加我的 sessionInfo():

R version 3.2.2 (2015-08-14)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 8 x64 (build 9200)

locale:
[1] LC_COLLATE=Persian_Iran.1256  LC_CTYPE=Persian_Iran.1256    LC_MONETARY=Persian_Iran.1256
[4] LC_NUMERIC=C                  LC_TIME=Persian_Iran.1256    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.9.6 foreign_0.8-65   RODBC_1.3-12     yaml_2.1.13     

loaded via a namespace (and not attached):
[1] tools_3.2.2  chron_2.3-47

P.S。对于那些有兴趣解决实际问题的人,我正在谈论的文件可以从以下网址下载:http://www.amar.org.ir/Portals/0/amarmozuii/hazinedaramad/80.rar (~18 MB)

this is not R's fault, or even MS-Access, as they each do fine with Persian.

这似乎是 RODBC 的限制,它似乎确实依赖 Windows 语言环境来解释 table 名称的字符编码。当我尝试

> tbls <- sqlTables(cns)
> head(tbls, 10)

我明白了

                    TABLE_CAT TABLE_SCHEM                 TABLE_NAME
1  C:\__tmp\zzzTest\80.MDB        <NA>          MSysAccessObjects
2  C:\__tmp\zzzTest\80.MDB        <NA>                   MSysACEs
3  C:\__tmp\zzzTest\80.MDB        <NA> MSysNavPaneGroupCategories
4  C:\__tmp\zzzTest\80.MDB        <NA>          MSysNavPaneGroups
5  C:\__tmp\zzzTest\80.MDB        <NA>  MSysNavPaneGroupToObjects
6  C:\__tmp\zzzTest\80.MDB        <NA>       MSysNavPaneObjectIDs
7  C:\__tmp\zzzTest\80.MDB        <NA>                MSysObjects
8  C:\__tmp\zzzTest\80.MDB        <NA>                MSysQueries
9  C:\__tmp\zzzTest\80.MDB        <NA>          MSysRelationships
10 C:\__tmp\zzzTest\80.MDB        <NA>    R80P1 ??????? 80 ??? ??

因为我的 Windows 语言环境英语(美国)无法识别 任何 Persian/Arabic 字符。此外,即使我直接指定其名称

,我也无法查询table
> RD <- sqlQuery(cns, 'SELECT Address FROM [R80P1 روستایی 80 بخش یک]')
> head(RD)
[1] "42S02 -1305 [Microsoft][ODBC Microsoft Access Driver] The Microsoft Access database engine cannot find the input table or query 'R80P1 <U+0631><U+0648><U+0633><U+062A><U+0627><U+06CC><U+06CC> 80 <U+0628><U+062E><U+0634> <U+06CC><U+06A9>'. Make sure it exists and that its name is spelled correctly."
[2] "[RODBC] ERROR: Could not SQLExecDirect 'SELECT Address FROM [R80P1 <U+0631><U+0648><U+0633><U+062A><U+0627><U+06CC><U+06CC> 80 <U+0628><U+062E><U+0634> <U+06CC><U+06A9>]'"                                                                                                                                

如果您不想重命名源数据库中的 table,那么您可以考虑以下解决方法:

  • 创建一个名为“80links.accdb”的新 Access 数据库。
  • 使用 External Data > Import & Link > Access 创建一个 linked table 指向源数据库中的 [R80P1 روستاوی 80 بخش یک] table ("80.MDB").
  • 重命名链接 table 以使用不带空格的英文名称,例如 [Section_80_rural_R80P1]
  • 运行 您对链接 table.
  • 的查询
> mdbfilename <- 'C:\__tmp\zzzTest\80links.accdb'
> cns <- odbcConnectAccess2007(mdbfilename)
> RD <- sqlQuery(cns, 'Select Address from Section_80_rural_R80P1')
> head(RD)
  Address
1   11001
2   11001
3   11001
4   11001
5   11001
6   11001