PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

plusieurs valeurs selectInput créent un comportement dplyr (postgres) inattendu

Le problème est la façon dont la requête est construite lorsque vous n'en sélectionnez qu'un un élément et utilisez le IN opérateur. Le dplyr traduction en SQL n'ajoute pas la parenthèse appropriée et échoue donc. Ce problème a été longuement discuté ici .

Une façon de contourner ce problème est de passer une instruction différente à filter() quand length d'entrée est égal à 1 (voir exemple ci-dessous).

Voici ce qui se passe :

tbl(mydb, "iris") %>%
  filter(Species %in% c("setosa", "versicolor")) %>%
  .$query

Donne le bon SQL syntaxe de requête :

<Query> SELECT "Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species"
FROM "iris"
WHERE "Species" IN ('setosa', 'versicolor')
<PostgreSQLConnection>

Et, s'il est exécuté, donne l'attendu :

#Source: postgres 9.3.13 [[email protected]:5432/csvdump]
#From: iris [100 x 5]
#Filter: Species %in% c("setosa", "versicolor") 
#
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#          (dbl)       (dbl)        (dbl)       (dbl)   (chr)
#1           5.1         3.5          1.4         0.2  setosa
#2           4.9         3.0          1.4         0.2  setosa
#3           4.7         3.2          1.3         0.2  setosa
#4           4.6         3.1          1.5         0.2  setosa
#5           5.0         3.6          1.4         0.2  setosa
#6           5.4         3.9          1.7         0.4  setosa
#7           4.6         3.4          1.4         0.3  setosa
#8           5.0         3.4          1.5         0.2  setosa
#9           4.4         2.9          1.4         0.2  setosa
#10          4.9         3.1          1.5         0.1  setosa
#..          ...         ...          ...         ...     ...

Voyons ce qui se passe si vous essayez de passer un seul élément :

tbl(mydb, "iris") %>%
  filter(Species %in% "setosa") %>%
  .$query

La requête sera :

<Query> SELECT "Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species"
FROM "iris"
WHERE "Species" IN 'setosa'
<PostgreSQLConnection>

Ce qui, s'il est exécuté, entraînera l'erreur suivante :

C'est parce que pour un seul élément, le dplyr traduction en SQL la requête n'ajoute pas la bonne parenthèse. Remarquez comment c'est 'setosa' au lieu de ('setosa') .

Pour contourner cela, nous pouvons faire :

if(length(input$Species) == 1) { 
  tbl(mydb, "iris") %>% 
    filter(Species == input$Species) %>% 
}

Qui construira un SQL syntaxiquement valide requête :

<Query> SELECT "Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species" 
FROM "iris" 
WHERE "Species" = 'setosa' 
<PostgreSQLConnection>

L'exemple suivant contourne ce problème. Ici, je demande simplement à l'application de passer filter(Species == ...) si input$Species est de length 1 et filter(Species %in% ...) Par ailleurs.

Application Shiny

server <- function(input, output) {

  selectedQuery <- reactive({

    if(length(input$Species) == 1) { 
      tbl(mydb, "iris") %>% 
        filter(Species == input$Species) %>% 
        .$query
    }
    else(
      tbl(mydb, "iris") %>% 
        filter(Species %in% input$Species) %>% 
        .$query
      )

  })

  selectedData <- reactive({

    if(length(input$Species) == 1) {
      tbl(mydb, "iris") %>% 
        filter(Species == input$Species) %>% 
        data.frame
    }
    else(
      tbl(mydb, "iris") %>% 
        filter(Species %in% input$Species) %>% 
        data.frame
      )
  })

  output$plot <- renderPlot({
    ggplot2::qplot(Sepal.Length, Petal.Length, data = selectedData(), color = Species)
  })

  output$query <- renderPrint({
    selectedQuery()
    })
}

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput("Species", "Species", 
                  tbl(mydb, "iris") %>% 
                    data.frame %>% 
                    .$Species %>% 
                    unique, 
                  selected = "setosa", multiple = TRUE)
    ),
    mainPanel(
      textOutput("query"),
      plotOutput("plot")
      )
  )
)

shinyApp(ui = ui, server = server)