如何使用R DBI传递data.frame for UPDATE

mch*_*hen 9 database r dataframe rodbc r-dbi

使用RODBC,有类似的功能sqlUpdate(channel, dat, ...)允许您传递dat = data.frame(...)而不必构建自己的SQL字符串.

但是,使用R的DBI,我看到的dbSendQuery(conn, statement, ...)只是一个字符串的函数,statement并没有机会data.frame直接指定.

那么如何UPDATE使用data.frameDBI?

R Y*_*oda 12

真的很晚,我的回答,但也许还有帮助...

在DBI/odbc包中没有单一的功能(我知道),但你可以使用准备好的更新语句复制更新行为(它应该比RODBC更快,sqlUpdate因为它将参数值作为批处理发送到SQL服务器:

library(DBI)
library(odbc)

con <- dbConnect(odbc::odbc(), driver="{SQL Server Native Client 11.0}", server="dbserver.domain.com\\default,1234", Trusted_Connection = "yes", database = "test")  # assumes Microsoft SQL Server

dbWriteTable(con, "iris", iris, row.names = TRUE)      # create and populate a table (adding the row names as a separate columns used as row ID)

update <- dbSendQuery(con, 'update iris set "Sepal.Length"=?, "Sepal.Width"=?, "Petal.Length"=?, "Petal.Width"=?, "Species"=? WHERE row_names=?')

# create a modified version of `iris`
iris2 <- iris
iris2$Sepal.Length <- 5
iris2$Petal.Width[2] <- 1
iris2$row_names <- rownames(iris)  # use the row names as unique row ID

dbBind(update, iris2)  # send the updated data

dbClearResult(update)  # release the prepared statement

# now read the modified data - you will see the updates did work
data1 <- dbReadTable(con, "iris")

dbDisconnect(con)
Run Code Online (Sandbox Code Playgroud)

只有当你拥有我在上面的例子中创建的主键时,才能使用行名称,这些行名称是每行增加1的唯一编号...

有关odbc我在DBI dbConnect语句中使用的包的更多信息,请参阅:https://github.com/rstats-db/odbc


mki*_*zon 5

基于 R Yoda 的答案,我为自己创建了下面的辅助函数。这允许使用数据帧来指定更新条件。

虽然我构建它是为了运行事务更新(即单行),但理论上它可以更新传递条件的多行。但是,这与使用输入数据帧更新多行不同。也许其他人可以在此基础上继续发展...


dbUpdateCustom = function(x, key_cols, con, schema_name, table_name) {
  
  if (nrow(x) != 1) stop("Input dataframe must be exactly 1 row")
  if (!all(key_cols %in% colnames(x))) stop("All columns specified in 'key_cols' must be present in 'x'")
  
  # Build the update string --------------------------------------------------

  df_key     <- dplyr::select(x,  one_of(key_cols))
  df_upt     <- dplyr::select(x, -one_of(key_cols))
  
  set_str    <- purrr::map_chr(colnames(df_upt), ~glue::glue_sql('{`.x`} = {x[[.x]]}', .con = con))
  set_str    <- paste(set_str, collapse = ", ")
  
  where_str  <- purrr::map_chr(colnames(df_key), ~glue::glue_sql("{`.x`} = {x[[.x]]}", .con = con))
  where_str  <- paste(where_str, collapse = " AND ")
  
  update_str <- glue::glue('UPDATE {schema_name}.{table_name} SET {set_str} WHERE {where_str}')
  
  # Execute ------------------------------------------------------------------
  
  query_res <- DBI::dbSendQuery(con, update_str)
  DBI::dbClearResult(query_res)

  return (invisible(TRUE))
}
Run Code Online (Sandbox Code Playgroud)

在哪里

  • x:1 行数据框,包含 1+ 个关键列和 1+ 个更新列。
  • key_cols:字符向量,包含 1 个或多个作为键的列名(即在 WHERE 子句中使用)