如何使用 tidyverse 在 R 中处理多个数据库连接和 select 语句

How to deal with multiple database connections and select statements in R with tidyverse

我正在使用 tidyverse 连接到具有相同数据结构(集群)的多个数据库。由于不同的数据库源,如果没有本地副本,就不可能合并。

我可以用长编码做任何事情,但现在我尝试在下面的问题中缩短代码运行。在为 select 语句定义列名时,dbplyr 将其与循环变量一起存储到连接中,而不是评估和存储字符串的结果。

这是一个最小的可重现示例:

library(tidyverse)

#reproducable example with two database and two tables in memory
con1 <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
con2 <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
copy_to(con1, mtcars)
copy_to(con1, iris)
copy_to(con2, mtcars)
copy_to(con2, iris)

#names of the tables
tables<-c("mtcars", "iris")

#specify which columns to select from which table
columns<-list("mtcars"=c("mpg", "hp"), 
              "iris"=c("Sepal.Length", "Sepal.Width"))

#list to put 
data_list<-vector(mode="list", length=length(tables))
names(data_list)<-tables

#loop over tables
for(i in tables){
  #loop over databases
  for(j in 1:2)
    data_list[[i]][[j]]<-tbl(get(paste0("con",j)), i)%>%select(columns[[i]])
}

这段代码到目前为止工作正常,但问题在于访问存储在列表 (data_list) 中的数据。

如果我尝试

data_list[[1]][[1]]

R 仍然评价

select(columns[[i]])

循环后 "iris" 语句给出错误信息:

错误:未知列 Sepal.LengthSepal.Width

对于 data_list 中的第二个列表,它工作正常,因为 i 设置合适:

data_list[[2]][[1]]

如何强制 select 语句计算表达式而不用循环变量 I 存储表达式?

在下一步中,我也想添加一个过滤表达式,这样我就不必收集所有数据,而只收集需要的数据。

如果联合会在没有副本的情况下处理数据库,那将解决所有问题

谢谢和最诚挚的问候 托马斯

嗯,你的意思是你想 select 列交互在你查询数据库之后

我编辑了您的代码以使用 tidyverse 函数(因为您已经加载)。

library(tidyverse)

# Reproducable example with two database and two tables in memory
con1 <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
con2 <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
copy_to(con1, mtcars)
copy_to(con1, iris)
copy_to(con2, mtcars)
copy_to(con2, iris)


# Specify which columns to select from which table
columns <-list("mtcars" = c("mpg", "hp"), "iris" = c("Sepal.Length", "Sepal.Width"))

# Loop over the table names (mtcars, iris) **and** the columns that belong to those datasets
data_list <-
  map2(names(columns), columns, ~ {

    # For each table/column combination, grab them from con1 and con2 and return them in a list
    con1_db <- tbl(con1, .x) %>% select(.y)
    con2_db <- tbl(con2, .x) %>% select(.y)
    list(con1_db, con2_db)
  }) %>%
  setNames(names(columns))

# With this you can interactively select the columns you wanted for each data. Just replace the dataset that you're interested in.
data_list %>%
  pluck("iris") %>%
  map(select, columns[['iris']])
#> [[1]]
#> Warning: `overscope_eval_next()` is deprecated as of rlang 0.2.0.
#> Please use `eval_tidy()` with a data mask instead.
#> This warning is displayed once per session.
#> Warning: `overscope_clean()` is deprecated as of rlang 0.2.0.
#> This warning is displayed once per session.
#> # Source:   lazy query [?? x 2]
#> # Database: sqlite 3.30.1 [:memory:]
#>    Sepal.Length Sepal.Width
#>           <dbl>       <dbl>
#>  1          5.1         3.5
#>  2          4.9         3  
#>  3          4.7         3.2
#>  4          4.6         3.1
#>  5          5           3.6
#>  6          5.4         3.9
#>  7          4.6         3.4
#>  8          5           3.4
#>  9          4.4         2.9
#> 10          4.9         3.1
#> # … with more rows
#> 
#> [[2]]
#> # Source:   lazy query [?? x 2]
#> # Database: sqlite 3.30.1 [:memory:]
#>    Sepal.Length Sepal.Width
#>           <dbl>       <dbl>
#>  1          5.1         3.5
#>  2          4.9         3  
#>  3          4.7         3.2
#>  4          4.6         3.1
#>  5          5           3.6
#>  6          5.4         3.9
#>  7          4.6         3.4
#>  8          5           3.4
#>  9          4.4         2.9
#> 10          4.9         3.1
#> # … with more rows