r - 如何从 R 在 PostgreSQL 中编写表?

标签 r postgresql

目前,要在 PostgreSQL 表中插入数据,我必须创建一个空表,然后执行 insert into table values ... 以及将数据框折叠成包含所有值的单个字符串.它不适用于大型数据框。

dbWtriteTable() 不适用于 PostgreSQL 并给出以下错误...

Error in postgresqlpqExec(new.con, sql4) : RS-DBI driver: (could not Retrieve the result : ERROR: syntax error at or near "STDIN" LINE 1: COPY "table_1" FROM STDIN

我已经按照之前提出的类似问题的建议尝试了以下 hack。这是链接... How do I write data from R to PostgreSQL tables with an autoincrementing primary key?

body_lines <- deparse(body(RPostgreSQL::postgresqlWriteTable))
new_body_lines <- sub(
  'postgresqlTableRef(name), "FROM STDIN")', 
  'postgresqlTableRef(name), "(", paste(shQuote(names(value)), collapse = ","), ") FROM STDIN")', 
  body_lines,
  fixed = TRUE
)
fn <- RPostgreSQL::postgresqlWriteTable
body(fn) <- parse(text = new_body_lines)
while("RPostgreSQL" %in% search()) detach("package:RPostgreSQL")
assignInNamespace("postgresqlWriteTable", fn, "RPostgreSQL")

这个 hack 仍然对我不起作用。 postgresqlWriteTable() 抛出完全相同的错误... 这到底是什么问题?

作为替代方案,我尝试使用 caroline 包中的 dbWriteTable2()。它会抛出一个不同的错误...

Error in postgresqlExecStatement(conn, statement, ...) : 
  RS-DBI driver: (could not Retrieve the result : ERROR:  column "id" does not exist in table_1
)
creating NAs/NULLs for for fields of table that are missing in your df
Error in postgresqlExecStatement(conn, statement, ...) : 
  RS-DBI driver: (could not Retrieve the result : ERROR:  column "id" does not exist in table_1
)

有没有其他方法可以直接将大型数据帧写入 PostgreSQL 中的表中?

最佳答案

好吧,我不确定为什么 dbWriteTable() 会失败;可能存在某种版本/协议(protocol)不匹配。也许您可以尝试安装最新版本的 R、RPostgreSQL 软件包,并在可能的情况下升级系统上的 PostgreSQL 服务器。

关于大数据的 insert into 解决方法失败,当必须移动大量数据并且一次性传输不可行/不切实际/不稳定时,IT 世界中经常做的是有时称为批处理batch processing .基本上,您将数据分成更小的 block 并一次发送每个 block 。

作为一个随机示例,几年前我编写了一些 Java 代码来从 HR LDAP 服务器查询员工信息,该服务器被限制为一次只能提供 1000 条记录。所以基本上我必须编写一个循环来继续发送相同的请求(使用 some kind of weird cookie-based mechanism 跟踪查询状态)并将记录累积到本地数据库中,直到服务器报告查询完成。

下面是一些代码,它手动构造 SQL 以根据给定的 data.frame 创建一个空表,然后使用参数化的批量大小将 data.frame 的内容插入到表中。它主要围绕调用 paste() 构建 SQL 字符串,调用 dbSendQuery() 发送实际查询。我还使用 postgresqlDataType() 来创建表。

## 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

请注意,与 dbWriteTable() 不同的是,我并没有费心在数据库表中添加一个 row.names 列,它似乎总是包含这样一个列(并且似乎没有提供任何阻止它的方法)。

关于r - 如何从 R 在 PostgreSQL 中编写表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37651470/

相关文章:

r - 使用 Rtexttools 库进行机器学习

r - R中数据帧中所有列组合的独立性卡方检验

r - (R) 如何从slide_index() 的窗口中排除每个当前行的值?

sql - 如何使用 PostgreSQL 从表名中获取列属性查询?

php - 使用 PostgreSQL 登录在 Silex 中不起作用

r - R 中的效果包可以用于没有截距的 lm 模型吗?

r - 如何将列作为行名放在数据框中

sql - 两个不同的选择进入同一个临时表

postgresql - 如何将卷挂载添加到正在运行的 postgreSQL 容器中?

postgresql - 如何将表格数据导出到文件