简体   繁体   English

根据 R Shiny App 中的用户输入创建动态 SQL 查询

[英]Create dynamic SQL query depending on user input in R Shiny App

I have an Shiny App where User can filter a SQL Database of Movies.我有一个 Shiny 应用程序,用户可以在其中过滤 SQL 电影数据库。 So far, you can only filter by different countries.到目前为止,您只能按不同国家/地区进行过滤。

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)

Now i want to give the user more Filters, for example Actor or Genre.现在我想给用户更多过滤器,例如演员或流派。 All Filters are Multiselect and optional.所有过滤器都是多选和可选的。 How can i create the Statement dynamic?如何创建动态声明? Would i use some switch statement for every possible combination (ie no Filter on Country but only Action Movies)?我会为每个可能的组合使用一些 switch 语句(即没有国家过滤器,但只有动作电影)? This seems ab it bit exhausting to me.这对我来说似乎有点累。

First off, you say the filter is optional but I see no way to disable it in your code.首先,您说过滤器是可选的,但我认为无法在您的代码中禁用它。 I'm assuming that deselecting all options is your way of disabling the filter, or at least that it's intended to work that way.我假设取消选择所有选项是您禁用过滤器的方式,或者至少它打算以这种方式工作。 If all options are selected for any filter, then the current approach should work fine, and will just show all films.如果为任何过滤器选择了所有选项,则当前方法应该可以正常工作,并且只会显示所有电影。

You can probably just construct the overall query piece by piece, and then paste it all together at the end.您可能只需要一块一块地构建整个查询,然后将它们全部粘贴到最后。

Base query: 'SELECT * FROM movies'基本查询:'SELECT * FROM movies'

Country filter: 'country in ' input country Country filter: 'country in' 输入国家

Actor filter: 'actor in' input actor演员过滤器:'演员在'输入演员

Genre filter: 'genre in' input genre流派过滤器:“流派”输入流派

Then you put it all together with paste.然后你把它们和粘贴一起放在一起。

To summarize: Base query.总结一下:基本查询。 Then, if any of the filters are active, add a WHERE.然后,如果任何过滤器处于活动状态,请添加 WHERE。 Join all filters together, separating by AND.将所有过滤器连接在一起,用 AND 分隔。 Pass the final query in as a direct string.将最终查询作为直接字符串传递。

You can even put the filters into a list for easier parsing.您甚至可以将过滤器放入列表中以便于解析。

# 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)"

Now use baseQuery as the direct query statement现在使用 baseQuery 作为直接查询语句

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM