簡體   English   中英

如何從 R 在 PostgreSQL 中寫表?

[英]How to write a table in PostgreSQL from R?

目前要在 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 作為回答之前提出的類似問題的建議。 這是鏈接... 如何使用自動遞增的主鍵將數據從 R 寫入 PostgreSQL 表?

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()會失敗; 可能存在某種版本/協議不匹配。 如果可能的話,也許您可​​以嘗試安裝最新版本的 R、RPostgreSQL 包,並升級系統上的 PostgreSQL 服務器。

關於insert into大數據的變通方法失敗,當必須移動大量數據並且一次性傳輸不可行/不切實際/不穩定時,IT 世界中經常執行的操作有時被稱為批處理批處理 基本上,您將數據分成較小的塊並一次發送一個塊。

作為一個隨機示例,幾年前我編寫了一些 Java 代碼來從 HR LDAP 服務器查詢員工信息,該服務器被限制為一次只能提供 1000 條記錄。 所以基本上我必須編寫一個循環來繼續發送相同的請求(使用某種奇怪的基於 cookie 的機制跟蹤查詢狀態)並將記錄累積到本地數據庫中,直到服務器報告查詢完成。

下面是一些代碼,它手動構造 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列,后者似乎總是包含這樣的列(並且似乎沒有提供任何阻止它的方法)。

我在處理這個例子時遇到了同樣的錯誤。

對我來說工作:

dbWriteTable(con, "cartable", value = df, overwrite = T, append = F, row.names = FALSE)

雖然我在 pgAdmin 中配置了一個表“cartable”。 所以存在一個空表,我不得不用值覆蓋該表。

因此,前面給出的顯示批處理的答案是 99.99% 正確的。 但是,由於 'insertBatch' 函數需要一個小參數,它在 Windows 上不起作用。 (無法為相同的答案添加評論)

'shQuote' 函數需要一個參數 type = 'cmd2' 才能工作。

但是,要在那里添加參數,您需要以下答案:

[https://stackoverflow.com/questions/6827299/r-apply-function-with-multiple-parameters][1]

因此,新的“insertBatch”函數變為:

 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,type = 'cmd2'))),");"); dbSendQuery(con,sql); }; invisible(); };

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM