如何在Oracle的dplyr :: semi_join中指定overwrite = T 1删除本地表 2复制本地表 3个通行证ID值

问题描述

在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=TRUEdplyr::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帮助程序功能