问题描述
在R中进行一些分析时,我需要能够进行semi_join(),以便在Oracle数据库表中获取所有值,而该数据库中本地R tibble中有匹配的行。
通常,我会这样:
con <- DBI::dbConnect(odbc::odbc(),"THEDATABASE")
db_tbl <- tbl(con,in_schema("OTHER_USER","table_I_care_about")
local_tbl <- tibble(x = 1:5,y = 5:10)
new_tbl_from_db <- db_tbl %>%
semi_join(local_tbl,by = 'x',copy =T)
有时这可行。但通常,我会收到此错误:
Error: Table "dbplyr_001" exists in database,and both overwrite and append are FALSE
(当然,它并不总是dbplyr_001,它几乎可以是任何数字)。
如果我查看数据库中的架构,就会发现存在名为dbplyr_001
的表,对此我并不感到惊讶。我不介意dbplyr写一些临时表。我尝试过手动将值插入此表,效果也很好。
我不知道怎么做是指定overwrite=TRUE
。我尝试将其作为进一步的参数传递给semi_join()
,但仍然遇到相同的错误。是否有一种简单的方法可以通过overwrite=TRUE
传递append=TRUE
或dplyr::semi_join()
?
解决方法
虽然不是直接解决方案,但其他三个选项是:
- 删除远程表
- 将本地表复制到命名表的数据库中
- 使用
%in%
传递ID值
下面每个代码。请注意,我使用的是SQL Server连接,因此某些数据库语法可能有所不同。其中几种方法都需要使用DBI
软件包,但是dbplyr
可能正在使用此软件包,因此您可能已经安装了此软件包。
1删除本地表
这里的想法是创建一个文本字符串,其中包含将表放入数据库的命令。然后使用dbExecute
软件包中的DBI
在数据库中执行此命令。
delete_table <- function(db_connection,db,schema,tbl_name){
# remove table if it exists
removal_query <- glue::glue("IF OBJECT_ID('{db}.{schema}.{tbl_name}','U') IS NOT NULL\n","DROP TABLE {db}{schema}.{tbl_name};")
result <- DBI::dbExecute(db_connection,as.character(removal_query))
2复制本地表
DBI
软件包还具有将本地表直接写入数据库的功能。
copy_r_to_sql <- function(db_connection,sql_table_name,r_table_name){
DBI::dbWriteTable(db_connection,DBI::Id(catalog = db,schema = schema,table = sql_table_name),r_table_name)
请注意,您将需要1.1.0或更高版本的DBI软件包。以前的版本无法写入用户指定的架构。
3个通行证ID值
如果本地表中的ID数量很少,则可以将它们作为%in%
子句的一部分进行传递。
id_list = local_table %>% select(x) %>% unlist()
new_tbl_from_db = db_tbl %>%
filter(x %in% id_list)
这会将所有ID放入远程WHERE子句中。如果您随后致电show_query(new_tbl_from_db)
,您应该会看到类似以下内容的信息:
SELECT *
FROM db.schema.tbl
WHERE x IN (1,2,3,4,5,....)
GitHub上的其他dbplyr帮助程序功能