我正在开发一个使用 dbplyr
查询数据库的 Shiny 应用程序,但我正在努力使用正确的语法来实现我常用的 dplyr
条件过滤器方法。看起来潜在的问题是 dbplyr 不允许您评估外部提供的向量,因此当用户提供潜在选项向量时,is.null 会失败。
<SQL>
SELECT *
FROM `mtcars`
WHERE (CASE WHEN (((4.0, 6.0) IS NULL)) THEN 1 WHEN (`cyl` IN (4.0, 6.0)) THEN 1 END)
最终,会有很多参数需要评估,所以我不想简单地将整个查询放在 if/else 语句中 as has been suggested in similar SO questions 。关于如何在基于 dbplyr
构建的 Shiny 应用程序中最好地实现条件过滤器,有什么建议吗?
# load libraries
library(dplyr)
library(dbplyr)
# create database and dataframe
mtcars_db <- tbl_memdb(mtcars)
mtcars_df <- collect(mtcars_db)
# parameterized filter function
filter_function <- function(data, user_selection) {
{{data}} |>
filter(
case_when(
is.null({{user_selection}}) ~ TRUE,
cyl %in% {{user_selection}} ~ TRUE
)
)
}
# save vector of user selections
cylinders <- c(4, 6)
# works with dataframes
filter_function(mtcars_df, NULL) # works
filter_function(mtcars_df, cylinders) # works
filter_function(mtcars_db, NULL) # works
filter_function(mtcars_db, cylinders) # fails
# show query of failing version
filter_function(mtcars_db, cylinders) |>
show_query()
最佳答案
我通常推荐@langtang 的方法,但在多种条件下,很明显这可能变得不切实际。
问题的原因是 SQL 没有办法测试整个列表(例如 (4.0, 6.0)
)是否为 null。因此,一个解决方案是仅测试列表的第一个值:
filter_function <- function(data, user_selection) {
data %>%
filter(
cyl %in% user_selection | is.null(local(user_selection[1]))
)
}
我使用 OR (|
) 代替 case_when
并删除了 {{ }}
,因为它无需使用即可。但这只是一种风格选择。
该解决方案的关键部分是local
,它强制在翻译之前对其内容进行评估。如果我们不包含 local
,则 dbplyr 会尝试翻译类似 (4.0, 6.0)[1]
的内容(但它无法执行此操作)。但是当我们使用 local
时,dbplyr 只需要翻译 4
(这很简单)。
这利用了 R 行为,即 NULL[1]
也是 NULL
。
我们必须假设 user_selection
永远不会将 NULL
作为第一个值。一般情况应该是这样。
关于r - Shiny 应用程序中 dbplyr 查询的条件过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75241005/