Jak połączyć R z bazą danych Access W 64-bitowym oknie?

Kiedy próbowałem połączyć R z bazą danych Access dostaję błąd

odbcConnectAccess is only usable with 32-bit Windows
Czy ktoś ma pomysł jak to rozwiązać?
library(RODBC) 
mdbConnect<-odbcConnectAccess("D:/SampleDB1/sampleDB1.mdb")
Author: Chris, 2012-10-25

6 answers

Zamiast tego użyj odbcDriverConnect. Jeśli masz zainstalowany 64-bitowy r, być może będziesz musiał użyć 32-bitowej kompilacji R.

odbcDriverConnect("Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=D:/SampleDB1/sampleDB1.mdb")
 21
Author: Matthew Plourde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-25 14:39:36

Oto jedna funkcja, która będzie przesyłać dane z 32-bitowego dostępu do 64-bitowego R bez konieczności zapisywania żadnych plików. Funkcja buduje łańcuch wyrażeń, który jest przekazywany do drugiej 32-bitowej sesji; dane są następnie zwracane do oryginalnej sesji za pomocą pakietu socket server (svSocket). Należy zauważyć, że serwer socket zapisuje dane dostępowe w środowisku globalnym, więc drugi parametr jest używany do definiowania wyjścia zamiast używania "

access_query_32 <- function(db_table = "qryData_RM", table_out = "data_access") {
  library(svSocket)

  # variables to make values uniform
  sock_port <- 8642L
  sock_con <- "sv_con"
  ODBC_con <- "a32_con"
  db_path <- "~/path/to/access.accdb"

  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("if('%1$s' %%in%% sqlTables(%2$s)$TABLE_NAME) {%1$s <- sqlFetch(%2$s, '%1$s')} else {%1$s <- 'table %1$s not found'}", db_table, 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, db_table))
    expr <- c(expr, "odbcCloseAll()")
    expr <- c(expr, sprintf("close(%s)", sock_con))
    expr <- paste(expr, collapse=";")

    # launch 32 bit R session and run expressions
    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)
  }
}

Czasami ta funkcja zwróci błąd, ale nie wpływa na pobieranie danych i wydaje się wynikać z zamknięcia połączenia z serwerem gniazda.

Jest prawdopodobnie miejsce na poprawę, ale zapewnia to prostą i szybką metodę pobierania danych do R z dostępu 32-bitowego.

 11
Author: manotheshark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-21 20:10:05

Nie udało się z udzielonymi odpowiedziami, ale tutaj jest podejście krok po kroku, które ostatecznie zrobił sztuczkę dla mnie. Miej Windows 8 na bitach 64. Z zainstalowanym 64 i 32-bitowym R. Mój Dostęp to 32 bit.

Kroki do użycia, zakładając dostęp 32-bitowy w systemie windows 8

  1. Select 32 bit R (is just a setting in R studio)
  2. wyszukaj w systemie windows skonfigurowane źródła danych ODBC (32-bitowe)
  3. przejdź do systemu DSN>Dodaj
  4. Wybierz sterownik do Microsoft Access (*.mdb) > Finish
  5. Nazwa źródła danych: ProjecnameAcc
  6. Opis: ProjectnameAcc
  7. Upewnij się, że faktycznie wybierz bazę danych > OK

Teraz mogę uruchomić kod, który mi się podobał

channel <- odbcConnect("ProjectnameAcc")
Table1Dat <- sqlFetch(channel, "Table1")
 6
Author: Dennis Jaheruddin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-21 11:47:49

Korzystając z porad innych, oto wyraźny przykład uzyskania 32-bitowych danych dostępowych do 64-bitowego R, które można zapisać w skrypcie, dzięki czemu nie trzeba wykonywać tych kroków ręcznie. Musisz mieć 32-bitowy R dostępny na komputerze, aby to uruchomić, a ten skrypt przyjmuje domyślną lokalizację dla 32-bitowego R, więc dostosuj w razie potrzeby.

Pierwsza część kodu trafia do głównego skryptu, druga część kodu to cała zawartość małego pliku skryptu R, który tworzysz i jest wywołana ze skryptu głównego, ta kombinacja wyodrębnia i zapisuje, a następnie ładuje dane z bazy danych access bez konieczności zatrzymywania się.

Oto bit, który idzie w moim skrypcie głównym, to jest uruchamiany z wewnątrz 64 bit R

##  Lots of script above here
## set the 32-bit script location
pathIn32BitRScript <- "C:/R_Code/GetAccessDbTables.R"
## run the 32 bit script
system(paste0(Sys.getenv("R_HOME"), "/bin/i386/Rscript.exe ",pathIn32BitRScript))
## Set the path for loading the rda files created from the little script 
pathOutUpAccdb <- "C/R_Work/"
## load the tables just created from that script
load(paste0(pathOutUpAccdb,"pots.rda"))
load(paste0(pathOutUpAccdb,"pans.rda"))
## Lots of script below here

Oto bit, który jest oddzielnym skryptem o nazwie GetAccessTables.R

library(RODBC).    
## set the database path
inCopyDbPath <- "C:/Projects/MyDatabase.accdb"
## connect to the database
conAccdb <- odbcConnectAccess2007(inCopyDbPath) 

## Fetch the tables from the database. Modify the as-is and string settings as desired
pots <- sqlFetch (conAccdb,"tbl_Pots",as.is=FALSE, stringsAsFactors = FALSE)
pans <- sqlFetch(conAccdb,"tbl_Pans",as.is=FALSE, stringsAsFactors = FALSE)
## Save the tables
save(pots, file = "C/R_Work/pots.rda")
save(pans, file = "C:/R_Work/pans.rda")
close(conAccdb)
 2
Author: jNorris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-11 15:04:34

Powyższa funkcja manotheshark jest bardzo przydatna, ale chciałem użyć zapytania SQL, a nie nazwy tabeli, aby uzyskać dostęp do bazy danych, a także przekazać nazwę bazy danych jako parametr, ponieważ zwykle pracuję z wieloma bazami danych Access. Oto zmodyfikowana wersja:

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)
  }
}

Miałem też pewne trudności z rozpracowaniem sposobu wywołania funkcji manotheshark i wymagało to trochę zagłębienia się w dokumentację pakietu svSocket, aby uświadomić sobie, że skrypt wywołujący musi utworzyć instancję obiekt, w którym zostaną zwrócone dane, a następnie przekazać swoją nazwę (nie sam obiekt) w parametrze table_out. Oto przykład skryptu R, który wywołuje moją zmodyfikowaną wersję:

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")
To działa, ale ma ograniczenia.

Po pierwsze, unikaj rozszerzeń Microsoft Access SQL. Na przykład, jeśli używasz Kreatora zapytań dostępu, często wstawia on nazwy pól, takie jak [TABLE_NAME]![FIELD_NAME]. To nie zadziała. Access umożliwia również niestandardowe nazwy pól zaczynające się od cyfry, takie jak "10kmsq" i pozwala używać ich w SQL jak SELECT [10kmSq] FROM .... To też nie zadziała. Jeżeli w składni SQL występuje błąd, zmienna zwrotna będzie zawierać komunikat o błędzie.

Po drugie, ilość danych, które możesz zwrócić, wydaje się być ograniczona do 64Kb. Jeśli spróbujesz uruchomić SQL, który zwróci zbyt dużo, sesja 32-bitowa nie zostanie zakończona, a skrypt zawiesi się.

 1
Author: Stuart Ball,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-31 11:47:13

Natknąłem się na to, więc napotykając podobny problem i w tym momencie mamy jeszcze co najmniej jedną opcję z niezwykle elastyczną biblioteką odbc.

Ważna uwaga: sterownik MS Access ODBC nie jest częścią domyślnej instalacji MS Office, więc będziesz musiał pobrać odpowiedni sterownik z Microsoft (Microsoft Access Database Engine 2016 Redistributable w moim przypadku) i pamiętaj, aby pobrać odpowiedni bitness (np AccessDatabaseEngine_X64.exe). Raz pobrany plik powinien automatycznie pojawić się w źródłach danych systemu Windows ODBC (64-bit) lub możesz potwierdzić wewnątrz sesji r za pomocą funkcji odbcListDrivers.

library(odbc)

# run if you want to see what drivers odbc has available
# odbcListDrivers()

# full file path to Access DB
file_path <- "~/some_access_file.accdb"

# pass MS Access file path to connection string
accdb_con <- dbConnect(drv = odbc(), .connection_string = paste0("Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=",file_path,";"))
 0
Author: Fiddler on the Roofies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-30 11:55:28