我就是这样写的。 sqldf 更自然地处理字符串,而不是使用nse。因此,只需传入要使用源的 data.frame 的字符串/名称即可。
library(sqldf); requireNamespace("checkmate")
db1 <- data.frame(a = c(1,2,3), d = c("a","b","c"), stringsAsFactors = F)
extract <- function( table_name, criteria_d ) {
checkmate::assert_character(table_name, min.chars=1, len=1, any.missing=F)
checkmate::assert_character(criteria_d, min.chars=1, len=1, any.missing=F)
# Half-way attempt to prevent sql-injection. Values would need to be only numbers, letters, and underscores.
checkmate::assert_character(table_name, pattern="^\\w+$", len=1, any.missing=F)
checkmate::assert_character(criteria_d, pattern="^\\w+$", len=1, any.missing=F)
sql <- paste0("select * from [", table_name , "] where d ='", criteria_d, "'")
cat("Executing: `", sql, "`\n", sep="")
sqldf(sql, verbose=F)
}
extract("db1", "b")
如果由于某种原因您不知道变量的字符串/名称,则等效:extract(quote(db1), "b")。
一些笔记。
- 我将变量的名称更改为“d”以使事情更清楚。
- 我认为
db2 和 db 与您的场景无关。
- 我尽量不要过多地更改您的代码。如果此函数曾经连接到真实数据库,请防范sql injection。
- 如果您的 sql 变得有点复杂,请考虑使用
glue::glue_sql()。
编辑以回应@Sayak 的评论:
使用purrr::map_df() 循环遍历data.frame的向量names
c("db1", "db2") %>%
purrr::map_df(extract, "b")
并将结果合并到一个单独的data.frame中:
Executing: `select * from [db1] where d ='b'`
Executing: `select * from [db2] where d ='b'`
a d
1 2 b
2 1 b
这非常巧妙,不需要后续调用dplyr::bind_rows()。
如果您需要更改标准(ie,因此它并不总是“b”),请使用 purrr::pmap_df() 将输入打包为 data.frame(其列与您的参数匹配extract()函数:
ds_input <- tibble::tribble(
~table_name, ~criteria_d,
"db1", "b",
"db1", "c",
"db2", "c"
)
ds_input %>%
purrr::pmap_df(extract)
# Executing: `select * from [db1] where d ='b'`
# Executing: `select * from [db1] where d ='c'`
# Executing: `select * from [db2] where d ='c'`
# a d
# 1 2 b
# 2 3 c
# 3 3 c