将R data.table
实例更新/插入SQL数据库(例如MySQL)的最简单方法是什么?我有一个data.table
的实例,其中配置了一些关键列(通过setkey
)。现在,每当表的主键列与表的键匹配时(或者我可以手动映射),我想update
对应的SQL表,但是对于那些键不匹配的行,insert
他们
最好我自己不需要为它编写SQL。一个原因是数据列数量相对较多。另一个原因是我想要数据库独立性(主要是在MySQL,PostgreSQL和SQLite之间轻松切换)。
答案 0 :(得分:1)
由于数据库中不同语法的变幻莫测,我认为很难避免使用特定于db的代码。
ANSI标准术语是MERGE
和(根据wikipedia)大多数大型商业数据库都支持ANSI标准。由于语法的相对新近度被添加到标准中,因此有许多非标准实现在数据库中具有不同的语法,您希望它可以移植。
dplyr等人完成的大部分数据库I / O.是通过包DBI。 DBI包有一个INSERT函数dbWriteTable()
,但文档很少。
RODBC包具有sqlUpdate()
功能,但它存在许多问题:
话虽如此 - 它可以适用于您的场景。如果没有,我将在下面展示如何构建UPSERT语句并使用RODBC以paramaterized方式执行它。它不是可移植的代码,但它是动态的,只需要很少的努力就可以传递列而不进行更新。
mysql中的默认UPSERT语法是INSERT INTO ... ON DUPLICATE KEY UPDATE ...
。这对于使用data.table的列名动态进行字符串构造非常容易。以下是为任何
library(data.table)
library(RODBC)
library(RODBCext)
irisDT<- data.table(iris, key="Species")
UPSERT<-function(DT, connectionString, destTable){
sql<- paste0("INSERT INTO ",destTable," (",paste(colnames(DT ),
collapse=","),")\n",
# This bit inserts the parameterised bit i.e. where your values will go
"VALUES (", paste(rep("?",ncol(DT )),
collapse=",",sep=",") ,")\n",
"ON DUPLICATE KEY UPDATE \n",
# This specifies on dup. key behaviour - doesn't include key
paste(colnames(DT )[!(colnames(DT ) %in% key(DT ))],
"=VALUE(",
colnames(DT )[!(colnames(DT ) %in% key(DT ))],
")", collapse=",\n", sep="")
)
RODBCext::sqlExecute(channel=connectionString,
query=sql,
data=DT
)
}
UPSERT(irisDT)
您可能需要略微调整字符串结构,因为我的MySQL语法可能有些偏差。
NB确保你在data.table上设置你的密钥在这里非常重要,否则你不能做一个UPSERT,除非你修改代码以排除特定的列但是我想要一个动态的解决方案对你而言。
@hadley在评论中表示。可以进行多步骤不可知过程,即
这将更加冗长,并且取决于新记录插入数据库表的速度可能会落在唯一性的约束和插入表中的新记录中,而不是插入一个重复的行。
答案 1 :(得分:1)
以下是修改sqlAppendTable
所做查询的另一种解决方案。
sql_query <- sqlAppendTable(con, "table", DT)
sql_query@.Data <- paste0(sql_query@.Data, "\n ","ON DUPLICATE KEY UPDATE col1 = values(col1), col2 = values(col2)")
dbSendQuery(con, sql_query)
更改col1
和col2
以了解应更新的列。根据需要添加其他人。可能您可以先确定主键并将其转换为通用函数。