How do I write data from R to PostgreSQL tables with an autoincrementing primary key?

后端 未结 2 1561
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-18 23:10

I have a table in a PostgreSQL database that has a BIGSERIAL auto-incrementing primary key. Recreate it using:

CREATE TABLE foo
(
  \"Id\" bigs         


        
相关标签:
2条回答
  • 2020-12-18 23:28

    From the thread in hrbrmstr's comment, I found a hack to make this work.

    In the postgresqlWriteTable in the RPostgreSQL package, you need to replace the line

    sql4 <- paste("COPY", postgresqlTableRef(name), "FROM STDIN")
    

    with

    sql4 <- paste(
      "COPY ", 
      postgresqlTableRef(name), 
      "(", 
      paste(postgresqlQuoteId(names(value)), collapse = ","), 
      ") FROM STDIN"
    )
    

    Note that the quoting of variables (not included in the original hack) is necessary to pass case-sensitive column names.

    Here's a script to do that:

    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")
    
    0 讨论(0)
  • 2020-12-18 23:54

    I struggled with an issue very similar to this today, and stumbled across this thread as I tried out different approaches. As of this writing (02/12/2018), it looks like the patch recommended above has been implemented into the latest version of RPostgreSQL::postgresqlWriteTable, but I still kept getting an error indicating that the primary key R assigned to my new rows was duplicated in the source data table.

    I ultimately implemented a workaround generating an incrementing primary key in R to append to my inserted data to update the source table in my postgreSQL Db. For my purposes, I only needed to insert one record into my table at a time and I can't imagine this is an optimal solution for inserting a batch of records requiring a serially incremented primary key. Predictably, an error of "table my_table exists in database: aborting assignTable" was thrown when I omitted the 'append=TRUE' from my script; however this option did not automatically assign an incrementing primary key as I had hoped, even with the code patch described above.

    drv <- dbDriver("PostgreSQL")
    localdb <- dbConnect(drv, dbname= 'MyDatabase',
                          host= 'localhost',
                        port = 5432,
                        user = 'postgres',
                        password= 'MyPassword')
    
    KeyPlusOne <- sum(dbGetQuery(localdb, "SELECT count(*) FROM my_table"),1)
    NewRecord <- t(c(KeyPlusOne, 'Var1','Var2','Var3','Var4'))
    NewRecord <- as.data.frame(NewRecord)
    NewRecord <- setNames(KeyPlusOne, c("PK","VarName1","VarName2","VarName3","VarName4"))
    
    postgresqlWriteTable(localdb, "my_table", NewRecord, append=TRUE, row.names=FALSE)
    
    0 讨论(0)
提交回复
热议问题