tsouchlarakis
tsouchlarakis

Reputation: 1619

R Shiny SQL Server Query

I would like to query an ODBC database within Shiny. All I need is for the user to be able to type in someone's ID number, for example, and then to print out the entire row in the table, which is located in the database. What I have so far allows for inputs, but does not seem to be querying the database and printing that information.

This is what I have:

library(RSQLite)
library(RODBC)
library(RODBCext)
library(sqldf)

#connect to database
dbhandle = odbcDriverConnect(...)


library(shiny)

ui <- shinyUI(

 pageWithSidebar(

   headerPanel("Hide Side Bar example"),
   sidebarPanel(
     textInput("Id", "Enter Account Number below"),
     submitButton(text="Submit")
   ),
   mainPanel(
   tabsetPanel(
    tabPanel("Data", tableOutput("tbTable"))
    )
  )
  )
)

server <- function(input, output) {
  myData <- reactive({

  #build query
  query = paste0("SELECT Fullname FROM Table WHERE ID= ", input$Id)

  #store results
  res <- sqlQuery(conn = dbhandle, query = query) 

  #close database
  databaseClose(dbhandle)

  #return results
  res
  })
}

shinyApp(ui = ui, server = server)

Any help is greatly appreciated! Thank you very much.

Upvotes: 2

Views: 4317

Answers (2)

Benjamin
Benjamin

Reputation: 17279

There are a handful of changes you'll need to make before this works. Some of the key concepts that need to be pointed out:

  1. You have no output$tbTable object. This means that your myData reactive is never being called, so you're never querying your database.
  2. You are using an RODBC database connection, and then using DBI style arguments in sqlQuery. You should use either DBI (via RSQLServer, perhaps--I've never used it) or RODBC (I use this a lot).
  3. You are closing dbhandle after the first time you call it. Is this the intended behavior? That the user should only get one chance at hitting the database?

Some minor notes:

  1. I recommend using RODBCext so that you can use parameterized queries.
  2. Table is a reserved word in SQL. I'm not sure if this is a placeholder or not, but it can be helpful to wrap your table components in brackets, such as [schema].[table_name].[column_name]
  3. You didn't direct the query to a schema. This may or may not present an issue. Since your query was never called, you didn't have a chance to see if it threw an error.

My recommendation for your code would be:

library(RODBCext) # Also loads RODBC
library(shiny)

ui <- shinyUI(

  pageWithSidebar(

    headerPanel("Hide Side Bar example"),
    sidebarPanel(
      textInput("Id", "Enter Account Number below"),
      submitButton(text="Submit")
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("Data", tableOutput("tbTable"))
      )
    )
  )
)

server <- function(input, output, session) {      
  myData <- reactive({
    req(input$Id)

    #connect to database 
    dbhandle = odbcDriverConnect(...)

    #build query
    query = "SELECT [Fullname] FROM [schema].[table_name] WHERE [ID] = ?"

    #store results
    res <- sqlExecute(channel = dbhandle, 
                      query = query,
                      data = list(input$Id),
                      fetch = TRUE,
                      stringsAsFactors = FALSE) 

    #close the connection
    odbcClose(dbhandle)
    #return results
    res
  })

  output$tbTable <- 
    renderTable(
      myData()
    )
}

shinyApp(ui = ui, server = server)

I seem to recall there is a way to close the database connection when the session closes, but I can't get it to work the way I expected with session$onSessionEnded(odbcClose(dbhandle)), so someone else may be able to fill in the gap there.

If you don't want to create a new connection everytime you click the button, you can create the connection outside of the reactive, and just not close it. This will leave a hanging connection, though, which I'm not fond of doing.

Upvotes: 4

HubertL
HubertL

Reputation: 19544

A reactive is a function : as long as you don't call it, it's not evaluated.

To fill in the table with the result of the query, you just have to add this code to your server function after the closing parenthesis of the reactive :

output$tbTable<- renderTable(mydata())

Upvotes: 0

Related Questions