Database 如何使用R DBI传递data.frame进行更新
使用,有一些函数,如Database 如何使用R DBI传递data.frame进行更新,database,r,dataframe,rodbc,r-dbi,Database,R,Dataframe,Rodbc,R Dbi,使用,有一些函数,如sqlUpdate(channel,dat,…),允许您传递dat=data.frame(…),而不必构造自己的SQL字符串 然而,对于R,我看到的只是像dbSendQuery(conn,statement,…)这样的函数,它只接受字符串语句,没有机会直接指定data.frame 那么,如何使用带有DBI的data.frame更新呢?我的答案是,真的很晚了,但可能还是有帮助的 DBI/odbc包中没有单个函数(我知道),但您可以使用准备好的update语句复制更新行为(该语句
sqlUpdate(channel,dat,…)
,允许您传递dat=data.frame(…)
,而不必构造自己的SQL字符串
然而,对于R,我看到的只是像dbSendQuery(conn,statement,…)
这样的函数,它只接受字符串语句
,没有机会直接指定data.frame
那么,如何使用带有DBI的
data.frame
更新呢?我的答案是,真的很晚了,但可能还是有帮助的
DBI/odbc包中没有单个函数(我知道),但您可以使用准备好的update语句复制更新行为(该语句应该比RODBC的sqlUpdate
更快,因为它将参数值作为批发送到SQL server:
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)
库(DBI)
数据库(odbc)
con基于R Yoda的答案,我将自己设置为下面的助手函数。这允许使用数据框指定更新条件
虽然我构建它是为了运行事务更新(即单行),但理论上它可以通过一个条件更新多行。但是,这与使用输入数据帧更新多行不同。也许其他人可以在此基础上构建
dbUpdateCustom=函数(x,键列,con,模式名,表名){
如果(nrow(x)!=1)停止(“输入数据帧必须正好是1行”)
如果(!all(key\u cols%在%colnames(x)中))停止(“key\u cols”中指定的所有列必须出现在“x”中)
#生成更新字符串--------------------------------------------------
df_key这里是我使用REPLACE-INTO组合起来的一个小助手函数,它使用DBI更新一个表,用新值替换旧的重复条目。它是基本的,适合我自己的需要,但应该很容易修改。您需要传递给该函数的只是连接、表名和数据帧。请注意,该表必须有一个主表我还包括了一个简单的工作示例
row_to_list <- function(Y) suppressWarnings(split(Y, f = row(Y)))
sql_val <- function(y){
if(!is.numeric(y)){
return(paste0("'",y,"'"))
}else{
if(is.na(y)){
return("NULL")
}else{
return(as.character(y))
}
}
}
to_sql_row <- function(x) paste0("(",paste(do.call("c", lapply(x, FUN = sql_val)), collapse = ", "),")")
bracket <- function(x) paste0("`",x,"`")
to_sql_string <- function(x) paste0("(",paste(sapply(x, FUN = bracket), collapse = ", "),")")
replace_into_table <- function(con, table_name, new_data){
#new_data <- data.table(new_data)
cols <- to_sql_string(names(new_data))
vals <- paste(lapply(row_to_list(new_data), FUN = to_sql_row), collapse = ", ")
query <- paste("REPLACE INTO", table_name, cols, "VALUES", vals)
rs <- dbExecute(con, query)
return(rs)
}
tb <- data.frame("id" = letters[1:20], "A" = 1:20, "B" = seq(.1,2,.1)) # sample data
dbWriteTable(con, "test_table", tb) # create table
dbExecute(con, "ALTER TABLE test_table ADD PRIMARY KEY (id)") # set primary key
new_data <- data.frame("id" = letters[19:23], "A" = 1:5, "B" = seq(101,105)) # new data
new_data[4,2] <- NA # add some NA values
new_data[5,3] <- NA
table_name <- "test_table"
replace_into_table(con, "test_table", new_data)
result <- dbReadTable(con, "test_table")
行到行列表谢谢,这适用于插入
,但是如何执行更新
?谢谢。我们尝试一次更新的行数有限制吗?我创建了一个执行合并的长sql语句,如果该语句太长,则dbGetQuery
返回0(受影响的0行)没有简单的答案,因为DBI包只定义了一个接口,并将实现留给不同的DBI兼容包。最终,所有限制都取决于符合DBI的驱动程序包(例如,odbc
)数据库加上DBI驱动程序包使用的二进制DB驱动程序。是否使用odbc
包?那么最好的方法是创建一个可复制的代码示例和数据库,并打开一个问题(要求修复或至少记录限制)在@RockScience,由于您描述的类似问题,我已经启动了一个DBI合规性检查“项目”在这里,我针对不同的DBI配置运行DBItest
单元测试,以估计每个DBI配置的成熟度、开放问题和限制。状态仍然是pre-alpha,我没有发布结果或从结果中得出任何结论,但您可以在(当然,试着根据您自己的配置运行测试)谢谢,非常令人印象深刻的工作!我一定会看一看。从我目前使用odbc和SQL Server看到的情况来看,有大量(>30k行)指定源值的合并失败,我必须发送到一个临时表,然后执行表之间的合并。我将检查如何在测试中进行翻译。如果您在此处发布一个新问题并举例说明错误,我将对此进行研究(请在此处添加链接,以便我可以找到您的问题)