如何处理多个数据库连接并使用tidyverse选择R中的语句

问题描述 投票:0回答:1

我正在使用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中的第二个列表,它工作正常,因为我设置得当:

data_list[[2]][[1]]

如何强制选择语句对表达式求值而不将表达式与循环变量I一起存储?

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

如果联合将处理没有副本的数据库,这将解决所有问题

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

r select tidyverse dbplyr
1个回答
0
投票

嗯,您是说要交互选择列之后您已查询数据库?

我已编辑您的代码以使用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
© www.soinside.com 2019 - 2024. All rights reserved.