【问题标题】:Create dynamic SQL query depending on user input in R Shiny App根据 R Shiny App 中的用户输入创建动态 SQL 查询
【发布时间】:2021-05-16 18:49:22
【问题描述】:

我有一个闪亮的应用程序,用户可以在其中过滤 SQL 电影数据库。到目前为止,您只能按不同国家/地区进行过滤。

con <- dbConnect(RSQLite::SQLite(), 'Movies.db')
movies_data <- dbReadTable(con, 'Movies')

ui <- fluidPage(
  fluidRow(
    selectInput(
      inputId = "country",
      label = "Country:",
      choices = movies_data$journal,
      multi=T
    ),
    br(),
    fluidRow(width="100%",
           dataTableOutput("table")
    )
  )
)

server <- function(input, output, session) {
        
  output$table <- renderDataTable({
    dbGetQuery(
      conn = con,
      statement = 'SELECT * FROM movies WHERE country IN ( ? )',
      params = list(input$country))
  })
}
shinyApp(ui = ui, server = server)

现在我想为用户提供更多过滤器,例如演员或流派。所有过滤器都是多选和可选的。如何创建动态声明?我会为每个可能的组合使用一些 switch 语句(即没有国家过滤器,但只有动作电影)?这对我来说似乎有点累。

【问题讨论】:

  • 如果您已经将整个数据库读入movies_data,为什么还要尝试生成动态闪亮?我希望使用 R 过滤等会更快(因为它已经在内存中)。
  • 我认为那并不理想。在最终产品中,我将使用另一种方法填充 inputselect。完整的数据真的很大,所以我不想将所有内容都加载到内存中。我可能会选择带有“UNIQE”的电影名称到列表或其他内容中。

标签: sql r sqlite shiny rsqlite


【解决方案1】:

首先,您说过滤器是可选的,但我认为无法在您的代码中禁用它。我假设取消选择所有选项是您禁用过滤器的方式,或者至少它打算以这种方式工作。如果为任何过滤器选择了所有选项,那么当前方法应该可以正常工作,并且只会显示所有电影。

您可能只是逐个构建整个查询,然后将它们全部粘贴到最后。

基本查询:'SELECT * FROM movies'

国家过滤器:'国家在'输入国家

演员过滤器:'演员在'输入演员

流派过滤器:'流派输入'输入流派

然后你用粘贴把它们放在一起。

总结:基本查询。然后,如果任何过滤器处于活动状态,请添加 WHERE。将所有过滤器连接在一起,用 AND 分隔。将最终查询作为直接字符串传入。

您甚至可以将过滤器放入列表中以便于解析。

# Here, filterList is a list containing input$country, input$actor, input$genre
# and filterNames contains the corresponding names in the database
# e.g. filterList <- list("c1", list("a1", "a2"), "g1")
# filterNames <- filterNames <- list("c", "a", "g")

baseQuery <- "SELECT * FROM movies"

# If any of the filters have greater than 0 value, this knows to do the filters
filterCheck <- any(sapply(filterList, length)>0)

# NOTE: If you have a different selection available for None
# just modify the sapply function accordingly

if(filterCheck)
{
  baseQuery <- paste(baseQuery, "WHERE")

  # This collapses multiselects for a filter into a single string with a comma separator
  filterList <- sapply(filterList, paste, collapse = ", ")

  # Now you construct the filters
  filterList <- sapply(1:length(filterList), function(x)
    paste0(filterNames[x], " IN (", filterList[x], ")"))

  # Paste the filters together
  filterList <- paste(filterList, collapse = " and ")

  baseQuery <- paste(baseQuery, filterList)
}

# Final output using the sample input above:
# "SELECT * FROM movies WHERE c IN (c1) and a IN (a1, a2) and g IN (g1)"

现在使用 baseQuery 作为直接查询语句

【讨论】:

  • 非常感谢! :)
猜你喜欢
  • 1970-01-01
  • 2022-01-20
  • 2018-03-22
  • 2021-02-07
  • 2020-11-13
  • 2020-01-23
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
相关资源
最近更新 更多