這是我如何寫它。 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