How to connect R with Access database in 64-bit Wi

2019-01-05 00:51发布

When I tried to connect R with Access database I get an error

odbcConnectAccess is only usable with 32-bit Windows

Does anyone has an idea how to solve this?

library(RODBC) 
mdbConnect<-odbcConnectAccess("D:/SampleDB1/sampleDB1.mdb")

7条回答
男人必须洒脱
2楼-- · 2019-01-05 01:26

The function by manotheshark above is very useful, but I wanted to use an SQL query, rather than a table name, to access the database and also to pass the database name as a parameter since I commonly work with a number of Access databases. Here is a modified version:

access_sql_32 <- function(db_sql = NULL, table_out = NULL, db_path = NULL) {
  library(svSocket)

  # variables to make values uniform
  sock_port <- 8642L
  sock_con <- "sv_con"
  ODBC_con <- "a32_con"

  if (file.exists(db_path)) {

    # build ODBC string
    ODBC_str <- local({
      s <- list()
      s$path    <- paste0("DBQ=", gsub("(/|\\\\)+", "/", path.expand(db_path)))
      s$driver  <- "Driver={Microsoft Access Driver (*.mdb, *.accdb)}"
      s$threads <- "Threads=4"
      s$buffer  <- "MaxBufferSize=4096"
      s$timeout <- "PageTimeout=5"
      paste(s, collapse=";")
    })

    # start socket server to transfer data to 32 bit session
    startSocketServer(port=sock_port, server.name="access_query_32", local=TRUE)

    # build expression to pass to 32 bit R session
    expr <- "library(svSocket)"
    expr <- c(expr, "library(RODBC)")
    expr <- c(expr, sprintf("%s <- odbcDriverConnect('%s')", ODBC_con, ODBC_str))
    expr <- c(expr, sprintf("%1$s <- sqlQuery(%3$s, \"%2$s\")", table_out, db_sql, ODBC_con))
    expr <- c(expr, sprintf("%s <- socketConnection(port=%i)", sock_con, sock_port))
    expr <- c(expr, sprintf("evalServer(%s, %s, %s)", sock_con, table_out, table_out))
    expr <- c(expr, "odbcCloseAll()")
    expr <- c(expr, sprintf("close(%s)", sock_con))
    expr <- paste(expr, collapse=";")

    # launch 32 bit R session and run the expression we built
    prog <- file.path(R.home(), "bin", "i386", "Rscript.exe")
    system2(prog, args=c("-e", shQuote(expr)), stdout=NULL, wait=TRUE, invisible=TRUE)

    # stop socket server
    stopSocketServer(port=sock_port)

    # display table fields
    message("Retrieved: ", table_out, " - ", paste(colnames(get(table_out)), collapse=", "))
  } else {
    warning("database not found: ", db_path)
  }
}

I also had some difficulty working out how to call manotheshark's function and it took some delving into the svSocket package documentation to realise that the calling script needs to instantiate the object in which the data will be returned and then to pass its NAME (not the object itself) in the table_out parameter. Here is an example of an R-script that calls my modified version:

source("scripts/access_sql_32.R")
spnames <- data.frame()
# NB. use single quotes for any embedded strings in the SQL
sql <- "SELECT name as species FROM checklist 
        WHERE rank = 'species' ORDER BY name"
access_sql_32(sql, "spnames", "X:/path/path/mydata.accdb")

This works, but has limitations.

Firstly, avoid any Microsoft Access SQL extensions. For example, if you use the Access Query builder, it will often insert field names like [TABLE_NAME]![FIELD_NAME]. These will not work. Also Access allows non-standard field names that start with a digit like "10kmSq" and allows you to use them in SQL like SELECT [10kmSq] FROM .... This also won't work. If there is an error in the SQL syntax, the return variable will contain an error message.

Secondly, the amount of data you can return appears to be limited to 64Kb. If you try to run SQL that returns too much, the 32-bit session does not terminate and the script hangs.

查看更多
登录 后发表回答