How to pass input variable to SQL statement in R shiny? - r

Usually, variables can be passed to SQL statements using paste. Interestingly this doesn't work with input variables in R shiny. Using the below code I get the following error message. How can I solve this?
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do
something that can only be done from inside a reactive expression or observer.)
--ui.R--
shinyUI(bootstrapPage(
selectInput(inputId = "segment",
label = "segment",
choices = c(1, 2, 3, 4),
selected = 1),
plotOutput(outputId = "main_plot", height = "300px")
))
--server.R--
shinyServer(function(input, output) {
database <- dbConnect(MySQL(), group= "zugangsdaten", dbname= 'database')
input<- input$segment
table <- dbGetQuery(database, statement =
paste("
SELECT a,b FROM table1
WHERE id = ",input,"
AND created_at>='2015-08-01'
"))
output$main_plot <- renderPlot({
plot(a,b)
})
})

The data query needs to be evaluated in a reactive context.
One way would be to move the data query itself into the renderPlot() context e.g.
--server.R--
shinyServer(function(input, output) {
database <- dbConnect(MySQL(), group= "zugangsdaten", dbname= 'database')
output$main_plot <- renderPlot({
table <- dbGetQuery(database, statement =
paste("
SELECT a,b FROM table1
WHERE id = ",input$segment,"
AND created_at>='2015-08-01'
"))
plot(table$a,table$b)
})
})
However, it's better to construct a reactive conductor for the data which can be evaluated once when any updates happen and re-used in multiple reactive end-points (see here for details).
This would look something like:
--server.R--
shinyServer(function(input, output) {
database <- dbConnect(MySQL(), group= "zugangsdaten", dbname= 'database')
table <- reactive({
dbGetQuery(database, statement =
paste("
SELECT a,b FROM table1
WHERE id = ",input$segment,"
AND created_at>='2015-08-01'
")
)
})
output$main_plot <- renderPlot({
plot(table()$a,table()$b)
})
})

For flexibility you can also use sub function to substitute part of the query string, this is quite clean approach
table <- reactive({
my_query <- 'SELECT a,b FROM table1 WHERE id = SOMETHING AND created_at >= 2015-08-01'
my_query <- sub("SOMETHING",input$segment,my_query)
dbGetQuery(database,noquote(my_query))
})

Related

Trying to use Shiny SelectBox to Grab Data from SQL Server Table

As the title says, I'm trying to get Shiny to display a SelectBox so I can dynamically select records from a SQL Server Table, and based on the selection of the CATEGORY, display everything in the table. The script below must be close. I am getting the SelectBox to work, but when I make a selection, nothing is displayed.
library(shiny)
library(RODBCext)
shinyApp(
ui =
shinyUI(
fluidPage(
uiOutput("select_category"),
tableOutput("display_data")
# plotOutput("plot_data")
)
),
server = shinyServer(function(input, output, session){
# A reactive object to get the query. This lets you use
# the data in multiple locations (plots, tables, etc) without
# having to perform the query in each output slot.
QueriedData <-
reactive({
req(input$showDrop)
ch <- odbcDriverConnect('driver={SQL Server};server=MyServer;database=Northwind;trusted_connection=true')
showList <- sqlExecute(ch,
"SELECT * FROM [NORTHWND].[dbo].[Customers] WHERE [CUSTOMERID] = ?",
data = list(AnalyteId = input$showDrop),
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
showList
})
# The select input control. These can be managed dynamically
# from the server, and then the control send back to the UI
# using `renderUI`
output$select_category <-
renderUI({
ch <- odbcDriverConnect('driver={SQL Server};server=MyServer;database=Northwind;trusted_connection=true')
showList <- sqlExecute(ch,
"SELECT DISTINCT AnalyteId From [NORTHWND].[dbo].[Customers] ORDER BY [CUSTOMERID]",
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
selectInput(inputId = "showDrop",
label = "Select Asset",
showList$AnalyteId)
})
# Display the data in a table
output$display_data <-
renderTable({
QueriedData()
})
# Display a plot
# output$plot_data <-
# renderPlot({
# plot(QueriedData()) # fill in the plot code you want to use.
# })
})
)
How can I get this working? Also, can you make the table dynamically selectable, or is that not an option?
It seems like you're missing some components. Some notes:
Your UI definition is invalid. Each argument to the UI should produce some kind of UI element. The lines where you define your connection and export the data from SQL Server will won't behave the way you are expecting them to here. You should either do these actions on the server, or you should define them globally.
You are retrieving data into your output$cumReturn slot, but you are using a renderPlot call to do it. This is somewhat disjoint. If you wish to render a plot, you should generate a plot. If you wish to show data, you should use renderTable (or something similar).
You also haven't displayed the cumReturn output slot anywhere in the UI, so the query is never actually being called.
Lastly, your query in output$cumReturn will fail when it goes to the server. I am guessing you mean to use input$showDrop in a WHERE statement, but your query has no such statement. This is not casting an error in the code above because you never try to render the cumReturn output, so the query is never being called.
Here's a variation on your code that should produce a table of data that fall within the category.
library(shiny)
library(RODBCext)
shinyApp(
ui =
shinyUI(
fluidPage(
uiOutput("select_category"),
tableOutput("display_data"),
plotOutput("plot_data")
)
),
server = shinyServer(function(input, output, session){
# A reactive object to get the query. This lets you use
# the data in multiple locations (plots, tables, etc) without
# having to perform the query in each output slot.
QueriedData <-
reactive({
req(input$showDrop)
ch <- odbcDriverConnect('...')
showList <- sqlExecute(ch,
"SELECT * FROM dbo.Analyte WHERE AnalyteId = ?",
data = list(AnalyteId = input$showDrop),
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
showList
})
# The select input control. These can be managed dynamically
# from the server, and then the control send back to the UI
# using `renderUI`
output$select_category <-
renderUI({
ch <- odbcDriverConnect('...')
showList <- sqlExecute(ch,
"SELECT DISTINCT AnalyteId FROM dbo.Analyte ORDER BY AnalyteId",
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
selectInput(inputId = "showDrop",
label = "Select Asset",
showList$AnalyteId)
})
# Display the data in a table
output$display_data <-
renderTable({
QueriedData()
})
# Display a plot
output$plot_data <-
renderPlot({
plot(QueriedData()) # fill in the plot code you want to use.
})
})
)
library(shiny)
library(RODBCext)
shinyApp(
ui =
shinyUI(
fluidPage(
uiOutput("select_category"),
tableOutput("display_data")
# plotOutput("plot_data")
)
),
# server needs the function; looks ok
server = shinyServer(function(input, output, session)
{
# A reactive object to get the query. This lets you use
# the data in multiple locations (plots, tables, etc) without
# having to perform the query in each output slot.
QueriedData <- reactive({
req(input$showDrop)
ch <- odbcDriverConnect("driver={SQL Server};server=SERVER;database=DB;trusted_connection=true")
showList <- sqlExecute(ch, "SELECT * FROM [DB].[dbo].[TABLE] WHERE Category = ?",
data = list(Category = input$showDrop),
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
showList
})
# The select input control. These can be managed dynamically
# from the server, and then the control send back to the UI
# using `renderUI`
output$select_category <- renderUI({
ch <- odbcDriverConnect("driver={SQL Server};server=SERVER;database=DB;trusted_connection=true")
showList <- sqlExecute(ch, "Select Distinct Category From [DB].[dbo].[TABLE] Order by Category",
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
selectInput(inputId = "showDrop",
label = "Select Asset",
showList$Category)
})
# Display the data in a table
output$display_data <- renderTable({
QueriedData()
})
# Display a plot
# output$plot_data <-
# renderPlot({
# plot(QueriedData()) # fill in the plot code you want to use.
# })
})
)

Not able to Render Data table

I am trying to render DataTable output to Shiny. Please find below explanation of my use case:
Connected to my database and got table data to df variable.
sent selected input from select input text box to server script.
Server script should take this input and get the data.
ui.R
library(shiny)
library(RODBC)
library(DBI)
# Establishing connection to ORE environment
dbconnect <- odbcConnect("orecloud", uid="XXXX", pwd="XXXXX", believeNRows=FALSE)
# Preparing data frames to get the data and show in select input pick list
df <- data.frame()
df <- sqlQuery(dbconnect,"SELECT distinct cpan FROM TABLE ")
shinyUI(fluidPage(
headerPanel("ORE XXX Summary"),
sidebarLayout(
sidebarPanel(
helpText("Please select Patient Details.."),
selectInput("CPAN",
label = "Choose patient",
choices = df,
selected = NULL),
submitButton(text = "Submit", icon = NULL)),
mainPanel(
dataTableOutput("tableoutput")
)
)
))
server.R
Server script should take the input and query the data from the table
Render the selected data to UI
If I change value in UI then it should display selected input data.
library(RODBC)
shinyServer(
function(input, output) {
dbconnect <- odbcConnect("orecloud", uid="oracle", pwd="Edvenswa2016", believeNRows=FALSE)
df2 <- data.frame()
input_var <- input$CPAN
print (input_var)
my_query <- paste("select * from CYTOKINE where CPAN= ", input_var)
print(myquery)
df2 <- sqlQuery(dbconnect,myquery)
output$tableoutput <- renderDataTable({df2})
}
)
You need to do it reactive
df2=reactive({
input_var <- input$CPAN
my_query <- paste("select * from CYTOKINE where CPAN= ", input_var)
sqlQuery(dbconnect,myquery)
})
and use like renderDataTable({df2()}) } )
If input$CPAN is character you need paste0("select * from CYTOKINE where CPAN= '", input_var,"'")
Also dont forget disconect
session$onSessionEnded(function() {
odbcClose(dbconnect )
})

Shiny - renaming factors in reactive data frame

I'm building a shiny app that queries an SQL database so the user can ggplot the data. I would like the user to be able to rename factors manually but am struggling to get going. Here is an example of what I want to do:
ui.R
library(markdown)
shinyUI(fluidPage(
titlePanel("Reactive factor label"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Input wafer ID:"), value = NULL),
actionButton("do", "Search wafer"),
textInput("text", label = h3("Factor name to change"), value = ""),
textInput("text", label = h3("New factor name"), value = ""),
actionButton("do2", "Change name")
),
mainPanel(
verbatimTextOutput("waf"),
verbatimTextOutput("que"),
verbatimTextOutput("pos"),
dataTableOutput(outputId="tstat")
)
)
)
)
server.R
# Create example data
Name <- factor(c("Happy", "New", "Year"))
Id <- 1:3
dd <- data.frame(Id, Name)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "dd", dd)
query <- function(...) dbGetQuery(con, ...)
wq = data.frame()
sq = data.frame()
shinyServer(function(input, output){
# create data frame to store reactive data set from query
values <- reactiveValues()
values$df <- data.frame()
# Wait for user to search
d <- eventReactive(input$do, { input$wafer })
# Reactive SQL query
a <- reactive({ paste0("Select * from dd where Id=",d()) })
wq <- reactive({ query( a() ) })
# Check outputs
output$waf <- renderPrint(input$wafer)
output$que <- renderPrint({ a() })
output$pos <- renderPrint( wq()[1,1] )
# observe d() so that data is not added until user presses action button
observe({
if (!is.null(d())) {
sq <- reactive({ query( a() ) })
# add query to reactive data frame
values$df <- rbind(isolate(values$df), sq())
}
})
output$tstat <- renderDataTable({
data <- values$df
})
})
In static R I would normally use data table to rename factors i.e.:
DT <- data.table(df)
DT[Name=="Happy", Name:="Sad"]
But I'm not sure how to go about this with a reactiveValues i.e. values$df.
I have read this (R shiny: How to get an reactive data frame updated each time pressing an actionButton without creating a new reactive data frame?). This lead me to try this but it doesn't do anything (even no error):
observeEvent(input$do2, {
DT <- data.table(values$df)
DT[Name == input$text1, Name := input$text2]
values$df <- data.frame(values$df)
})
Perhaps there is a way around this..maybe there is a way to use an action button to "lock in" the data as a new data frame, which can then be used to rename?
Sorry for such a long winded question. My real app is much longer and more complex. I have tried to strip it down.
Your approach works but there are a few issues in your app.
In ui.R, both textInput have the same id, they need to be different so you can refer to them in the server.R. In the observeEvent you posted, you refer to input$text1 and input$text2 so you should change the id of the textInputs to text1 and text2.
In the observeEvent you posted, the last line should be values$df <- as.data.frame(DT), otherwise it does not change anything.

Working with reactiveValues and ggplot in shiny

Im using R and shiny to query an SQL database. The user can search and add to a reactive data frame, the output of which is plotted in ggplot. However, I need to change the columns of the reactive data frames to factors for plotting. I can do this directly with ggplot (aes(factor(...), ). However, if I add the option of changing the plotted variable using a reactive input, I must use aes_string. If I use aes_string it does not like aes(factor(...),. Here is a working example:
Server:
# Create example data
set.seed(10)
MeasurementA <- rnorm(1000, 5, 2)
MeasurementB <- rnorm(1000, 5, 2)
Wafer <- rep(c(1:100), each=10)
ID <- rep(c(101:200), each=10)
Batch <- rep(c(1:10), each=100)
dd <- data.frame(Batch, Wafer, ID, MeasurementA, MeasurementB)
# Create local connection (in reality this will be a connection to a host site)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "dd", dd)
query <- function(...) dbGetQuery(con, ...)
# Create empty data frames to populate
wq = data.frame()
sq = data.frame()
shinyServer(function(input, output){
# create data frame to store reactive data set from query
values <- reactiveValues()
values$df <- data.frame()
# Action button for first query
d <- eventReactive(input$do, { input$wafer })
# First stage of reactive query
a <- reactive({ paste("Select ID from dd where Wafer=",d(), sep="") })
wq <- reactive({ query( a() ) })
# Output to confirm query is correct
output$que <- renderPrint({ a() })
output$pos <- renderPrint( wq()[1,1] )
# Action button to add results from query to a data frame
e <- eventReactive(input$do2, { wq()[1,1] })
b <- reactive({ paste("select Wafer, Batch, MeasurementA, MeasurementB from dd where ID=",e()," Order by ID asc ;", sep="") })
# observe e() so that data is not added until user presses action button
observe({
if (!is.null(e())) {
sq <- reactive({ query( b() ) })
# add query to reactive data frame
values$df <- rbind(isolate(values$df), sq())
}
})
# output of results
# Without mesurement choice (works)
output$boxV <- renderPlot({
ggplot(values$df, aes(factor(Wafer), MeasurementA, fill=factor(Batch))) + geom_boxplot()
})
# With measurement choice (doesnt work)
#output$boxV <- renderPlot({
#ggplot(values$df, aes_string(factor('Wafer'), input$char, fill=factor('Batch'))) + geom_boxplot()
#})
})
UI:
library(markdown)
shinyUI(fluidPage(
titlePanel("Generic grapher"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Input wafer ID:"), value = NULL),
actionButton("do", "Search wafer"),
actionButton("do2", "Add to data frame"),
selectInput("char", label="Boxplot choice:",
choices = list("A"="MeasurementA", "B"="MeasurementB"),
selected="Von.fwd")
),
mainPanel(
verbatimTextOutput("que"),
verbatimTextOutput("pos"),
plotOutput("boxV")
)
)
)
)
Ive added output plot code for both working and non-working (non-working is commented out).
Now, ive read this (Formatting reactive data.frames in Shiny) and this (R shiny modify reactive data frame) but im confused. Because im using reactiveValues to store data, I use the code values$df to access the data...but what if i I want to turn a column to a factor for purpose of above? this doesnt seem to work:
new <- reactive(as.factor(values$df$Wafer))
Perhaps I am barking up the wrong tree with this?
Ok, I solved the problem by changing the data type within the query itself:
b <- reactive({ paste("select cast(Wafer as varchar) as Wafer, cast(Batch as varchar) as Batch, MeasurementA, MeasurementB from dd where ID=",e()," Order by ID asc ;", sep="") })
That way I didnt have to mess about afterwards. It works for me but if anyone reading this wants to tell me that its a bad idea, please do. Im new to SQL and R so please correct me so I can learn. Thanks

R-Shiny using Reactive renderUI value

How do you use values obtained from a renderUI element in a reactive wrapper?
i.e. My code:
CompanyNames <- sqlQuery(connection, "SELECT Companynm FROM RiskMgm_Company")
output$CompNameSelector <- renderUI({
selectInput("compName","Company Name:",as.vector(CompanyNames[,1]))
})
CompID <- reactive({
CompID <<- sqlQuery(paste("SELECT CompanyID FROM RiskMgm_Company WHERE Companynm = '",compName,"'"))
})
output$MotorSelector <- renderUI({
selectInput("MachSer","Machine:",sqlQuery(connection,paste("SELECT Motor_func FROM RiskMgm_Motor WHERE Company_ID='",CompID,"'")))
})
My error:
Successfilly opened connection to db
Error in paste("SELECT CompanyID FROM RiskMgm_Company WHERE Companynm = '", :
could not find function "compName"
What am I doing wrong? Essentially what I want is a list of companies given by the SQL query. Then depending on the Company selected it will show the motors that belong to that company in the next dropdown box
Thanks
You would refer to the elements by their id for example input$compName. As a contrived example here
is a simple shiny app with two selectInput's. The second selectInput choices depend on the value of the first. Referencing the output of widgets created by renderUI is no different from referencing the same widgets if they had been in UI.R from the beginning:
library(shiny)
myDF <- data.frame(A = 1:4, B = 3:6, C = 6:9, D = 10:13)
runApp(
list(
ui = fluidPage(
uiOutput("myList"),
uiOutput("myNumbers")
)
, server = function(input, output, session){
output$myList <- renderUI({
selectInput("compName", "Company Name:", LETTERS[1:4])
})
output$myNumbers <- renderUI({
selectInput("compNo", "Product Line:", myDF[, input$compName])
})
}
)
)

Resources