【问题标题】:dplyr:: append to postgresql remote source if uid not presentdplyr:: 如果 uid 不存在,则附加到 postgresql 远程源
【发布时间】:2018-09-02 23:49:19
【问题描述】:

除非我遗漏了什么,否则文档中没有提及如何在实践中使用诸如 db_write_table 之类的函数。包文档中唯一的参考是。

db_write_table(con, table, types, values, temporary = FALSE, ...)

types 没有解释。 dplyr 的远程连接功能似乎在任何地方都没有详细记录,例如dplyr.tidyverse.org.

我有一个数据库mydb 和表mydata 我可以连接

require(RPostgreSQL)
require(dplyr)

drv <- dbDriver("PostgreSQL")
sapply(dbListConnections(drv), dbDisconnect)
con <- dbConnect(drv, dbname = "mydb", host = "localhost", port = 5432, user = "username")
data_db = tbl(con, 'mydata')

远程数据tbl data_db 包含一个名为uid 的字段。我有一个 data_frame dat,如果它们的 dat$uid 值不存在,我需要将观察结果附加到 mydata

这可以通过db_write_table 完成还是需要 SQL 方法?

【问题讨论】:

    标签: r dplyr rpostgresql


    【解决方案1】:

    根据@hadley 对此answer 的评论,您可以使用dbWriteTable(append = TRUE)。这是一个使用 SQLite 的示例:

    library(dplyr)
    
    # Create some example data
    con <- DBI::dbConnect(RSQLite::SQLite(), path = ":dbname:")
    dd <- data.frame(uid = 1:20, value = LETTERS[1:20])
    dat <- data.frame(uid = 15:26, value = LETTERS[15:26])
    copy_to(con, dd, "my_data",
      temporary = FALSE, 
      indexes = list("uid", "value")
    )
    
    # Identify rows to append
    dd_db <- tbl(con, "my_data")
    dd_uid <- select(dd_db, uid) %>%
      collect() %>%
      unlist()
    dat_to_append <- filter(dat, !(uid %in% dd_uid))
    
    DBI::dbWriteTable(con, "my_data", dat_to_append, append = TRUE)
    

    【讨论】:

    • 感谢伟煌。对于大型数据库,我发现这可能存在性能问题:整个数据库 uid 字段在每次追加之前下载,即使只有 1 条记录。我猜最好使用dat_matched &lt;- select(dd_db, uid) %&gt;% filter(uid %in% dat$uid) %&gt;% collect 并附加anti_join(dat, dat_matched, by="uid") 的结果
    • 啊,同意。你的方法更明智。
    【解决方案2】:

    因此,值得的是我的实现,它应该对我的情况表现更好(小附加到大数据库):

    db_add_unmatched = function(con, remote, dat, uid, append = TRUE, row.names = FALSE){
      tbl_remote = tbl(con, remote)
      dat_matched = select(tbl_remote, uid) %>% filter(uid %in% dat[[uid]]) %>% collect
      if(nrow(dat_matched) == 0){
        dat_unmatched = dat
      } else dat_unmatched = anti_join(dat, dat_matched, by = uid)
      if(nrow(dat_unmatched) > 0){
        DBI::dbWriteTable(con, remote, dat_unmatched, append = append, row.names = row.names)
      } else message('No unmatched rows to add')
    }
    
    db_add_unmatched(con, 'mydata', dat, 'uid')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-26
      • 1970-01-01
      • 2014-03-17
      • 1970-01-01
      相关资源
      最近更新 更多