Shiny应用程序中dbplyr查询的条件过滤器

wyyhbhjk  于 2023-01-28  发布在  其他
关注(0)|答案(2)|浏览(136)

我正在开发一个使用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()
bbuxkriu

bbuxkriu1#

如果在is.null(user_selection)时返回data,则filter函数适用于所有四种用例:

filter_function <- function(data, user_selection) {
  if(is.null(user_selection)) return(data)
  filter(data, case_when(cyl %in% {{user_selection}} ~ TRUE))
}
bf1o4zei

bf1o4zei2#

我通常推荐@langtang的方法,但在多种情况下,这显然是不切实际的。
问题的原因是SQL没有办法测试整个列表(例如(4.0, 6.0))是否为空。因此,一个解决方案是只测试列表的第一个值:

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(这是微不足道的)。
这利用了NULL[1]也是NULL的R行为。
我们必须假设user_selection从来没有NULL作为第一个值,通常情况应该是这样。

相关问题