This is how I'd write it. sqldf more naturally handles strings, rather than using nse. So just pass in the string/name of the data.frame you want to use a source.
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")
If for some reason you couldn't know the string/name of the variable, this is equivalent: extract(quote(db1), "b")
.
A few notes.
- I changed the name of the variable to 'd' to make things more clear.
- I assumed that
db2
and db
weren't relevant to your scenario.
- I tried not to change your code too much. If this function is ever connected to a real database, protect against sql injection.
- If your sql gets a little more complicated, consider using
glue::glue_sql()
.
Edit in response to @Sayak's comment:
Use purrr::map_df()
to loop through a vector of data.frame names
c("db1", "db2") %>%
purrr::map_df(extract, "b")
and combines the results into a single data.frame:
Executing: `select * from [db1] where d ='b'`
Executing: `select * from [db2] where d ='b'`
a d
1 2 b
2 1 b
This is pretty slick that it doesn't require a subsequent call to dplyr::bind_rows()
.
If you need to vary the criteria (ie, so it's not always "b"), use purrr::pmap_df()
with packaging the inputs as a data.frame (whose columns match the parameters of your extract()
function:
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