这是我如何写它。 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 名
c("db1", "db2") %>%
purrr::map_df(extract, "b")
的载体和结合的结果成单个数据帧:
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()
。
如果需要改变标准(即,所以它并不总是“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
您的SQL表达式格式不正确。使用这一行,你会很好的去:'Example = paste0(“select * from”,'x',“where b ='”,“b”,“'”,collapse =“”)''。请记住测试函数的内部部分以确保它们产生预期的输出。 – lmo