RODBC 与 ms-access 错误 07002 17 [Microsoft][ODBC Microsoft Access Driver]COUNT 字段不正确

Posted

技术标签:

【中文标题】RODBC 与 ms-access 错误 07002 17 [Microsoft][ODBC Microsoft Access Driver]COUNT 字段不正确【英文标题】:RODBC with ms-access error 07002 17 [Microsoft][ODBC Microsoft Access Driver]COUNT field incorrect 【发布时间】:2021-05-06 16:01:50 【问题描述】:

问题:

我有一个小型数据库,MS Access 运行良好。使用RODBC 包,我使用sqlSave 创建一个带有data.frame 的新表。我尝试使用sqlSaveappend=TRUE 将记录直接添加到表中,但是得到一个我无法附加到该表的一般错误,我不知道为什么会这样。因此,我在 R 中构建了一个 INSERT sql-string,然后使用 sqlQuery 将中间表中的值插入到最终表中。之后,从数据库中删除中间表。我有几个函数可以以这种方式对其他表执行此任务,并且它们都可以正常工作,只有这个不想表现。

我知道 sql-string 有效,因为我可以在 Access 中直接使用这两个表运行确切的 sql 语句,并且没有问题。但是,当我在我编写的函数的上下文中运行查询时,我收到错误07002 17 [Microsoft][ODBC Microsoft Access Driver]COUNT field incorrect。根据来自 MS 开发者论坛的 this SO post 和 this thread,我希望确保我正在转义任何列名,并且我已经正确引用了这些列,并且数据类型从我的 data.frame 匹配到数据库表。但是,还是不行。

代码:

# the devDB argument is the file path to the database on my machine, 
# and is defined in my session environment

insertFunction <- function(df, devDB)
  
  sqlStat <- "INSERT INTO tbl_Source ( ID, [Set], Source, [Source Desc], Type, [Age (d)], [On Product?], Formulation, [AB Program], [Date Rec] )
                SELECT intermediaryTable.ID, intermediaryTable.[Set], intermediaryTable.Source, 
                intermediaryTable.SourceDesc, intermediaryTable.Type, intermediaryTable.Aged, 
                intermediaryTable.OnProduct, intermediaryTable.Formulation, intermediaryTable.ABProgram, intermediaryTable.DateRec
                FROM intermediaryTable;"
  
  res <- tryCatch(
    
      # establish the connection to whichever DB
      chan <- RODBC::odbcDriverConnect(connection = paste("Driver=Microsoft Access Driver (*.mdb, *.accdb);DBQ=", devDB, sep = ""), case = "nochange")
      
      # if the intermediary table remains from the last update, remove it from the DB
      if(any(grepl("intermediaryTable", RODBC::sqlTables(channel = chan)$TABLE_NAME)))
        RODBC::sqlQuery(chan, query = "DROP TABLE intermediaryTable;")
      
      
      # save the data.frame as a table in the database
      RODBC::sqlSave(channel = chan, dat = df, tablename = "intermediaryTable", rownames = FALSE)

      # run the sqlStat char string from above to add the records, and save the 
      # output to log the update status in a log file
      dbUpdateStatus <- RODBC::sqlQuery(channel = chan, query = sqlStat)
    ,
    error = function(cond)
      return(paste("Error occurred! ", cond, " timestamp:",Sys.time()))
    
  )
  
  RODBC::sqlQuery(channel = chan, query = "DROP TABLE intermediaryTable;")
  RODBC::odbcClose(channel = chan)
  rm(chan)
  
  return(res)

会话信息:

R version 3.6.1 (2019-07-05)
Platform: i386-w64-mingw32/i386 (32-bit)
Running under: Windows 10 x64 (build 18363)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                           LC_TIME=English_United States.1252    

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

other attached packages:
[1] magrittr_2.0.1

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.6       fansi_0.4.2      assertthat_0.2.1 utf8_1.1.4       crayon_1.4.1     dplyr_1.0.4     
 [7] R6_2.5.0         odbc_1.3.0       DBI_1.1.1        lifecycle_1.0.0  pillar_1.5.0     rlang_0.4.10    
[13] blob_1.2.1       vctrs_0.3.6      generics_0.1.0   ellipsis_0.3.1   RODBC_1.3-16     tools_3.6.1     
[19] bit64_4.0.5      glue_1.4.2       bit_4.0.4        purrr_0.3.4      hms_1.0.0        compiler_3.6.1  
[25] pkgconfig_2.0.3  tidyselect_1.1.0 tibble_3.1.0 

使用的 ODBC 驱动程序是 Access Database Engine 2010,available here。

代表

表结构

表名:tbl_Source

ID:自动编号(长整数) 设置:双 来源:双 来源描述:短文本 类型:短文本 年龄(d):双倍 关于产品?:短文本 公式:短文本 AB 程序:短文本 日期记录:日期/时间

样本数据:

df <- data.frame(
  ID = c(12495:12497),
  Set = rep(998, 3),
  Source = c(1:3),
  SourceDesc = c("Desc 1", "Desc 2", "Desc 3"),
  Type = c("Type1", "Type2", "Type3"),
  Aged = c(28, 24, 5),
  OnProduct = c("No", "No", "Yes"),
  Formulation = rep(NA, 3),
  ABProgram = rep(NA, 3),
  DateRec = rep("04/01/2021", 3)
)

示例数据df 共享与顶部的insertFunction 代码一起使用的列名。

请让我知道是否有其他人认为缺少其他任何内容作为代表。

谢谢!

【问题讨论】:

【参考方案1】:

我之前注意到使用 RODBC 的奇怪之处,并且可以使用 RODBC 重现该问题,但 DBI 工作正常。由于我看到您的环境包含 DBI 和 odbc,我强烈建议您使用它。如果让我猜的话,我猜是因为 RODBC 没有单独的执行函数,而且那里出了点问题。

让我们翻译你的代码:

library(DBI) 
# I've noted some peculiarities when not attaching DBI, though this code seems to run without it

insertFunction <- function(df, devDB)
  
  sqlStat <- "INSERT INTO tbl_Source ( ID, [Set], Source, [Source Desc], Type, [Age (d)], [On Product?], Formulation, [AB Program], [Date Rec] )
                SELECT intermediaryTable.ID, intermediaryTable.[Set], intermediaryTable.Source, 
                intermediaryTable.SourceDesc, intermediaryTable.Type, intermediaryTable.Aged, 
                intermediaryTable.OnProduct, intermediaryTable.Formulation, intermediaryTable.ABProgram, intermediaryTable.DateRec
                FROM intermediaryTable;"
  
  res <- tryCatch(
    
      # establish the connection to whichever DB
      chan <- DBI::dbConnect(odbc::odbc(), .connection_string = paste0("Driver=Microsoft Access Driver (*.mdb, *.accdb);DBQ=", devDB))
      
      # We don't need to remove the table when it exists, since we specify `overwrite = T`
      # save the data.frame as a table in the database
      # We need to specify batch_rows = 1 since Access does not support batch inserts through DBI
      DBI::dbWriteTable(chan, df, name = "intermediaryTable", batch_rows = 1, overwrite = T)

      # run the sqlStat char string from above to add the records, and save the 
      # output to log the update status in a log file
      dbUpdateStatus <- DBI::dbExecute(chan, sqlStat) # Note: this won't match RODBCs output
    ,
    error = function(cond)
      return(paste("Error occurred! ", cond, " timestamp:",Sys.time()))
    
  )
  # If the try-catch fails due to a connection problem, the following line will likely fail too, and the database connection won't close
  DBI::dbExecute(chan, "DROP TABLE intermediaryTable;")
  DBI::dbDisconnect(chan)
  rm(chan)
  
  return(res)

请注意,通常最好直接追加到目标表,而不是写入中介然后追加,DBI 可以使用dbAppendTable 做到这一点。

【讨论】:

感谢您的回复!过去,对于这些类型的数据库事务,我对 RODBC 没有任何问题。从字面上看,它只是从这张桌子开始的。我什至将上面的函数与其他 data.frames 和表一起使用,它工作正常。我确实经常将 DBI 用于我的 SELECT 查询,然后使用 RODBC,因为它允许批量插入。我不知道这个项目将来会有多大,所以想保留这个功能。我会尝试实施您的建议,然后稍后标记为已回答或未回答。 我尝试了您使用DBI 的建议,但仍然遇到同样的问题。另一部分是使用dbAppendTable() 也不起作用。它没有返回错误消息,只是没有在控制台中返回任何输出。

以上是关于RODBC 与 ms-access 错误 07002 17 [Microsoft][ODBC Microsoft Access Driver]COUNT 字段不正确的主要内容,如果未能解决你的问题,请参考以下文章

RODBC - 值不适合数字

RODBC 功能和错误/警告

使用 CASE WHEN 语句时出现 RODBC“无效字符\n”错误

尝试连接数据库时出现 RODBC 错误代码 202

使用 R studio 连接到 dashDB 的 RODBC

RODBC 错误:无法 SQLExecDirect