Ok, non sono sicuro del perché dbWriteTable()
fallirebbe; potrebbe esserci una sorta di mancata corrispondenza tra versione/protocollo. Forse potresti provare a installare le ultime versioni di R, il pacchetto RPostgreSQL e ad aggiornare il server PostgreSQL sul tuo sistema, se possibile.
Riguardo a insert into
soluzione alternativa che non riesce per dati di grandi dimensioni, ciò che viene spesso fatto nel mondo IT quando è necessario spostare grandi quantità di dati e un trasferimento one-shot non è fattibile/non pratico/instabile è ciò che a volte viene definito batching o elaborazione batch
. Fondamentalmente, dividi i dati in blocchi più piccoli e invii ogni blocco uno alla volta.
Come esempio casuale, alcuni anni fa ho scritto del codice Java per richiedere informazioni sui dipendenti da un server LDAP HR che era vincolato a fornire solo 1000 record alla volta. Quindi in pratica ho dovuto scrivere un ciclo per continuare a inviare la stessa richiesta (con lo stato della query monitorato utilizzando una specie di strano meccanismo basato sui cookie ) e accumulando i record in un database locale fino a quando il server non ha segnalato il completamento della query.
Ecco del codice che costruisce manualmente l'SQL per creare una tabella vuota basata su un dato data.frame, quindi inserisce il contenuto di data.frame nella tabella usando una dimensione batch parametrizzata. È principalmente costruito attorno a chiamate a paste()
per creare le stringhe SQL e dbSendQuery()
per inviare le domande effettive. Uso anche postgresqlDataType()
per la creazione della tabella.
## connect to the DB
library('RPostgreSQL'); ## loads DBI automatically
drv <- dbDriver('PostgreSQL');
con <- dbConnect(drv,host=...,port=...,dbname=...,user=...,password=...);
## define helper functions
createEmptyTable <- function(con,tn,df) {
sql <- paste0("create table \"",tn,"\" (",paste0(collapse=',','"',names(df),'" ',sapply(df[0,],postgresqlDataType)),");");
dbSendQuery(con,sql);
invisible();
};
insertBatch <- function(con,tn,df,size=100L) {
if (nrow(df)==0L) return(invisible());
cnt <- (nrow(df)-1L)%/%size+1L;
for (i in seq(0L,len=cnt)) {
sql <- paste0("insert into \"",tn,"\" values (",do.call(paste,c(sep=',',collapse='),(',lapply(df[seq(i*size+1L,min(nrow(df),(i+1L)*size)),],shQuote))),");");
dbSendQuery(con,sql);
};
invisible();
};
## generate test data
NC <- 1e2L; NR <- 1e3L; df <- as.data.frame(replicate(NC,runif(NR)));
## run it
tn <- 't1';
dbRemoveTable(con,tn);
createEmptyTable(con,tn,df);
insertBatch(con,tn,df);
res <- dbReadTable(con,tn);
all.equal(df,res);
## [1] TRUE
Nota che non mi sono preoccupato di anteporre un row.names
colonna nella tabella del database, a differenza di dbWriteTable()
, che sembra includere sempre tale colonna (e non sembra fornire alcun mezzo per prevenirla).